Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/certbot/certbot.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrien Ferrand <adferrand@users.noreply.github.com>2022-01-25 02:16:19 +0300
committerGitHub <noreply@github.com>2022-01-25 02:16:19 +0300
commitdac0b2c187fd94de9725da623587729ef356b60d (patch)
tree0ff4671df80dc94e6d9e2d620031507d8533776c
parent7198f43008e05ecc0feb37814e0a1f2f520caf3a (diff)
Typed jose fields (#9073)
* Add generic methods to save some casts, and fix lint * Update current and oldest pinning * Fix classes * Remove some todos thanks to josepy 1.11.0 * Cleanup some useless pylint disable * Finish complete typing * Better TypeVar names * Upgrade pinning and fix some typing errors * Use protocol * Fix types in apache Co-authored-by: Brad Warren <bmw@users.noreply.github.com>
-rw-r--r--acme/acme/challenges.py66
-rw-r--r--acme/acme/client.py41
-rw-r--r--acme/acme/crypto_util.py13
-rw-r--r--acme/acme/fields.py19
-rw-r--r--acme/acme/jws.py18
-rw-r--r--acme/acme/messages.py220
-rw-r--r--acme/acme/standalone.py5
-rw-r--r--acme/setup.py3
-rw-r--r--acme/tests/fields_test.py4
-rw-r--r--certbot-apache/certbot_apache/_internal/configurator.py25
-rw-r--r--certbot-apache/certbot_apache/_internal/http_01.py12
-rw-r--r--certbot-ci/certbot_integration_tests/utils/misc.py3
-rw-r--r--certbot-compatibility-test/certbot_compatibility_test/test_driver.py2
-rw-r--r--certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py12
-rw-r--r--certbot-nginx/certbot_nginx/_internal/configurator.py7
-rw-r--r--certbot-nginx/certbot_nginx/_internal/http_01.py6
-rw-r--r--certbot-nginx/certbot_nginx/_internal/nginxparser.py10
-rw-r--r--certbot/certbot/_internal/account.py8
-rw-r--r--certbot/certbot/_internal/auth_handler.py15
-rw-r--r--certbot/certbot/_internal/client.py2
-rw-r--r--certbot/certbot/_internal/plugins/manual.py2
-rw-r--r--certbot/certbot/_internal/plugins/standalone.py2
-rw-r--r--certbot/certbot/_internal/plugins/webroot.py8
-rw-r--r--certbot/certbot/_internal/reporter.py2
-rw-r--r--certbot/certbot/_internal/snap_config.py4
-rw-r--r--certbot/certbot/crypto_util.py5
-rw-r--r--certbot/certbot/plugins/common.py4
-rw-r--r--certbot/certbot/plugins/dns_test_common_lexicon.py4
-rw-r--r--certbot/certbot/tests/acme_util.py4
-rw-r--r--tools/oldest_constraints.txt66
-rw-r--r--tools/pinning/current/pyproject.toml4
-rw-r--r--tools/requirements.txt127
32 files changed, 398 insertions, 325 deletions
diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py
index de842a261..94d121a21 100644
--- a/acme/acme/challenges.py
+++ b/acme/acme/challenges.py
@@ -12,6 +12,8 @@ from typing import Mapping
from typing import Optional
from typing import Tuple
from typing import Type
+from typing import TypeVar
+from typing import Union
from cryptography.hazmat.primitives import hashes
import josepy as jose
@@ -27,6 +29,8 @@ from acme.mixins import TypeMixin
logger = logging.getLogger(__name__)
+GenericChallenge = TypeVar('GenericChallenge', bound='Challenge')
+
class Challenge(jose.TypedJSONObjectWithFields):
# _fields_to_partial_json
@@ -34,9 +38,10 @@ class Challenge(jose.TypedJSONObjectWithFields):
TYPES: Dict[str, Type['Challenge']] = {}
@classmethod
- def from_json(cls, jobj: Mapping[str, Any]) -> 'Challenge':
+ def from_json(cls: Type[GenericChallenge],
+ jobj: Mapping[str, Any]) -> Union[GenericChallenge, 'UnrecognizedChallenge']:
try:
- return super().from_json(jobj)
+ return cast(GenericChallenge, super().from_json(jobj))
except jose.UnrecognizedTypeError as error:
logger.debug(error)
return UnrecognizedChallenge.from_json(jobj)
@@ -47,7 +52,7 @@ class ChallengeResponse(ResourceMixin, TypeMixin, jose.TypedJSONObjectWithFields
"""ACME challenge response."""
TYPES: Dict[str, Type['ChallengeResponse']] = {}
resource_type = 'challenge'
- resource = fields.Resource(resource_type)
+ resource: str = fields.resource(resource_type)
class UnrecognizedChallenge(Challenge):
@@ -62,6 +67,7 @@ class UnrecognizedChallenge(Challenge):
:ivar jobj: Original JSON decoded object.
"""
+ jobj: Dict[str, Any]
def __init__(self, jobj: Mapping[str, Any]) -> None:
super().__init__()
@@ -85,7 +91,7 @@ class _TokenChallenge(Challenge):
"""Minimum size of the :attr:`token` in bytes."""
# TODO: acme-spec doesn't specify token as base64-encoded value
- token: bytes = jose.Field(
+ token: bytes = jose.field(
"token", encoder=jose.encode_b64jose, decoder=functools.partial(
jose.decode_b64jose, size=TOKEN_SIZE, minimum=True))
@@ -108,10 +114,10 @@ class _TokenChallenge(Challenge):
class KeyAuthorizationChallengeResponse(ChallengeResponse):
"""Response to Challenges based on Key Authorization.
- :param unicode key_authorization:
+ :param str key_authorization:
"""
- key_authorization = jose.Field("keyAuthorization")
+ key_authorization: str = jose.field("keyAuthorization")
thumbprint_hash_function = hashes.SHA256
def verify(self, chall: 'KeyAuthorizationChallenge', account_public_key: jose.JWK) -> bool:
@@ -126,7 +132,7 @@ class KeyAuthorizationChallengeResponse(ChallengeResponse):
:rtype: bool
"""
- parts = self.key_authorization.split('.')
+ parts = self.key_authorization.split('.') # pylint: disable=no-member
if len(parts) != 2:
logger.debug("Key authorization (%r) is not well formed",
self.key_authorization)
@@ -152,6 +158,9 @@ class KeyAuthorizationChallengeResponse(ChallengeResponse):
return jobj
+# TODO: Make this method a generic of K (bound=KeyAuthorizationChallenge), response_cls of type
+# Type[K] and use it in response/response_and_validation return types once Python 3.6 support is
+# dropped (do not support generic ABC classes, see https://github.com/python/typing/issues/449).
class KeyAuthorizationChallenge(_TokenChallenge, metaclass=abc.ABCMeta):
"""Challenge based on Key Authorization.
@@ -168,7 +177,7 @@ class KeyAuthorizationChallenge(_TokenChallenge, metaclass=abc.ABCMeta):
"""Generate Key Authorization.
:param JWK account_key:
- :rtype unicode:
+ :rtype str:
"""
return self.encode("token") + "." + jose.b64encode(
@@ -229,7 +238,7 @@ class DNS01Response(KeyAuthorizationChallengeResponse):
around `KeyAuthorizationChallengeResponse.verify`.
:param challenges.DNS01 chall: Corresponding challenge.
- :param unicode domain: Domain name being verified.
+ :param str domain: Domain name being verified.
:param JWK account_public_key: Public key for the key pair
being authorized.
@@ -257,7 +266,7 @@ class DNS01(KeyAuthorizationChallenge):
"""Generate validation.
:param JWK account_key:
- :rtype: unicode
+ :rtype: str
"""
return jose.b64encode(hashlib.sha256(self.key_authorization(
@@ -266,7 +275,8 @@ class DNS01(KeyAuthorizationChallenge):
def validation_domain_name(self, name: str) -> str:
"""Domain name for TXT validation record.
- :param unicode name: Domain name being validated.
+ :param str name: Domain name being validated.
+ :rtype: str
"""
return "{0}.{1}".format(self.LABEL, name)
@@ -293,7 +303,7 @@ class HTTP01Response(KeyAuthorizationChallengeResponse):
"""Simple verify.
:param challenges.SimpleHTTP chall: Corresponding challenge.
- :param unicode domain: Domain name being verified.
+ :param str domain: Domain name being verified.
:param JWK account_public_key: Public key for the key pair
being authorized.
:param int port: Port used in the validation.
@@ -357,7 +367,7 @@ class HTTP01(KeyAuthorizationChallenge):
def path(self) -> str:
"""Path (starting with '/') for provisioned resource.
- :rtype: string
+ :rtype: str
"""
return '/' + self.URI_ROOT_PATH + '/' + self.encode('token')
@@ -368,8 +378,8 @@ class HTTP01(KeyAuthorizationChallenge):
Forms an URI to the HTTPS server provisioned resource
(containing :attr:`~SimpleHTTP.token`).
- :param unicode domain: Domain name being verified.
- :rtype: string
+ :param str domain: Domain name being verified.
+ :rtype: str
"""
return "http://" + domain + self.path
@@ -378,7 +388,7 @@ class HTTP01(KeyAuthorizationChallenge):
"""Generate validation.
:param JWK account_key:
- :rtype: unicode
+ :rtype: str
"""
return self.key_authorization(account_key)
@@ -409,7 +419,7 @@ class TLSALPN01Response(KeyAuthorizationChallengeResponse):
) -> Tuple[crypto.X509, crypto.PKey]:
"""Generate tls-alpn-01 certificate.
- :param unicode domain: Domain verified by the challenge.
+ :param str domain: Domain verified by the challenge.
:param OpenSSL.crypto.PKey key: Optional private key used in
certificate generation. If not provided (``None``), then
fresh key will be generated.
@@ -433,8 +443,8 @@ class TLSALPN01Response(KeyAuthorizationChallengeResponse):
port: Optional[int] = None) -> crypto.X509:
"""Probe tls-alpn-01 challenge certificate.
- :param unicode domain: domain being validated, required.
- :param string host: IP address used to probe the certificate.
+ :param str domain: domain being validated, required.
+ :param str host: IP address used to probe the certificate.
:param int port: Port used to probe the certificate.
"""
@@ -450,7 +460,7 @@ class TLSALPN01Response(KeyAuthorizationChallengeResponse):
def verify_cert(self, domain: str, cert: crypto.X509) -> bool:
"""Verify tls-alpn-01 challenge certificate.
- :param unicode domain: Domain name being validated.
+ :param str domain: Domain name being validated.
:param OpensSSL.crypto.X509 cert: Challenge certificate.
:returns: Whether the certificate was successfully verified.
@@ -523,7 +533,7 @@ class TLSALPN01(KeyAuthorizationChallenge):
"""Generate validation.
:param JWK account_key:
- :param unicode domain: Domain verified by the challenge.
+ :param str domain: Domain verified by the challenge.
:param OpenSSL.crypto.PKey cert_key: Optional private key used
in certificate generation. If not provided (``None``), then
fresh key will be generated.
@@ -531,9 +541,10 @@ class TLSALPN01(KeyAuthorizationChallenge):
:rtype: `tuple` of `OpenSSL.crypto.X509` and `OpenSSL.crypto.PKey`
"""
- return self.response(account_key).gen_cert(
+ # TODO: Remove cast when response() is generic.
+ return cast(TLSALPN01Response, self.response(account_key)).gen_cert(
key=kwargs.get('cert_key'),
- domain=kwargs.get('domain'))
+ domain=cast(str, kwargs.get('domain')))
@staticmethod
def is_supported() -> bool:
@@ -599,13 +610,12 @@ class DNS(_TokenChallenge):
:rtype: DNSResponse
"""
- return DNSResponse(validation=self.gen_validation(
- account_key, **kwargs))
+ return DNSResponse(validation=self.gen_validation(account_key, **kwargs))
def validation_domain_name(self, name: str) -> str:
"""Domain name for TXT validation record.
- :param unicode name: Domain name being validated.
+ :param str name: Domain name being validated.
"""
return "{0}.{1}".format(self.LABEL, name)
@@ -620,7 +630,7 @@ class DNSResponse(ChallengeResponse):
"""
typ = "dns"
- validation = jose.Field("validation", decoder=jose.JWS.from_json)
+ validation: jose.JWS = jose.field("validation", decoder=jose.JWS.from_json)
def check_validation(self, chall: 'DNS', account_public_key: jose.JWK) -> bool:
"""Check validation.
@@ -631,4 +641,4 @@ class DNSResponse(ChallengeResponse):
:rtype: bool
"""
- return chall.check_validation(cast(jose.JWS, self.validation), account_public_key)
+ return chall.check_validation(self.validation, account_public_key)
diff --git a/acme/acme/client.py b/acme/acme/client.py
index ae2f261aa..7e87e7474 100644
--- a/acme/acme/client.py
+++ b/acme/acme/client.py
@@ -19,6 +19,7 @@ from typing import cast
from typing import Dict
from typing import Iterable
from typing import List
+from typing import Mapping
from typing import Optional
from typing import Set
from typing import Text
@@ -33,6 +34,7 @@ from requests.adapters import HTTPAdapter
from requests.utils import parse_header_links
from requests_toolbelt.adapters.source import SourceAddressAdapter
+from acme import challenges
from acme import crypto_util
from acme import errors
from acme import jws
@@ -156,12 +158,12 @@ class ClientBase:
authzr = messages.AuthorizationResource(
body=messages.Authorization.from_json(response.json()),
uri=response.headers.get('Location', uri))
- if identifier is not None and authzr.body.identifier != identifier:
+ if identifier is not None and authzr.body.identifier != identifier: # pylint: disable=no-member
raise errors.UnexpectedUpdate(authzr)
return authzr
- def answer_challenge(self, challb: messages.ChallengeBody, response: requests.Response
- ) -> messages.ChallengeResource:
+ def answer_challenge(self, challb: messages.ChallengeBody,
+ response: challenges.ChallengeResponse) -> messages.ChallengeResource:
"""Answer challenge.
:param challb: Challenge Resource body.
@@ -176,15 +178,15 @@ class ClientBase:
:raises .UnexpectedUpdate:
"""
- response = self._post(challb.uri, response)
+ resp = self._post(challb.uri, response)
try:
- authzr_uri = response.links['up']['url']
+ authzr_uri = resp.links['up']['url']
except KeyError:
raise errors.ClientError('"up" Link header missing')
challr = messages.ChallengeResource(
authzr_uri=authzr_uri,
- body=messages.ChallengeBody.from_json(response.json()))
- # TODO: check that challr.uri == response.headers['Location']?
+ body=messages.ChallengeBody.from_json(resp.json()))
+ # TODO: check that challr.uri == resp.headers['Location']?
if challr.uri != challb.uri:
raise errors.UnexpectedUpdate(challr.uri)
return challr
@@ -492,7 +494,7 @@ class Client(ClientBase):
updated[authzr] = updated_authzr
attempts[authzr] += 1
- if updated_authzr.body.status not in (
+ if updated_authzr.body.status not in ( # pylint: disable=no-member
messages.STATUS_VALID, messages.STATUS_INVALID):
if attempts[authzr] < max_attempts:
# push back to the priority queue, with updated retry_after
@@ -599,7 +601,7 @@ class Client(ClientBase):
:raises .ClientError: If revocation is unsuccessful.
"""
- self._revoke(cert, rsn, self.directory[cast(str, messages.Revocation)])
+ self._revoke(cert, rsn, self.directory[messages.Revocation])
class ClientV2(ClientBase):
@@ -756,7 +758,7 @@ class ClientV2(ClientBase):
for url in orderr.body.authorizations:
while datetime.datetime.now() < deadline:
authzr = self._authzr_from_response(self._post_as_get(url), uri=url)
- if authzr.body.status != messages.STATUS_PENDING:
+ if authzr.body.status != messages.STATUS_PENDING: # pylint: disable=no-member
responses.append(authzr)
break
time.sleep(1)
@@ -897,11 +899,11 @@ class BackwardsCompatibleClientV2:
check_tos_cb(tos)
if self.acme_version == 1:
client_v1 = cast(Client, self.client)
- regr = client_v1.register(regr)
- if regr.terms_of_service is not None:
- _assess_tos(regr.terms_of_service)
- return client_v1.agree_to_tos(regr)
- return regr
+ regr_res = client_v1.register(regr)
+ if regr_res.terms_of_service is not None:
+ _assess_tos(regr_res.terms_of_service)
+ return client_v1.agree_to_tos(regr_res)
+ return regr_res
else:
client_v2 = cast(ClientV2, self.client)
if "terms_of_service" in client_v2.directory.meta:
@@ -970,7 +972,8 @@ class BackwardsCompatibleClientV2:
'certificate, please rerun the command for a new one.')
cert = OpenSSL.crypto.dump_certificate(
- OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped).decode()
+ OpenSSL.crypto.FILETYPE_PEM,
+ cast(OpenSSL.crypto.X509, cast(jose.ComparableX509, certr.body).wrapped)).decode()
chain_str = crypto_util.dump_pyopenssl_chain(chain).decode()
return orderr.update(fullchain_pem=(cert + chain_str))
@@ -1056,7 +1059,7 @@ class ClientNetwork:
pass
def _wrap_in_jws(self, obj: jose.JSONDeSerializable, nonce: str, url: str,
- acme_version: int) -> jose.JWS:
+ acme_version: int) -> str:
"""Wrap `JSONDeSerializable` object in JWS.
.. todo:: Implement ``acmePath``.
@@ -1064,7 +1067,7 @@ class ClientNetwork:
:param josepy.JSONDeSerializable obj:
:param str url: The URL to which this object will be POSTed
:param str nonce:
- :rtype: `josepy.JWS`
+ :rtype: str
"""
if isinstance(obj, VersionedLEACMEMixin):
@@ -1082,7 +1085,7 @@ class ClientNetwork:
if self.account is not None:
kwargs["kid"] = self.account["uri"]
kwargs["key"] = self.key
- return jws.JWS.sign(jobj, **kwargs).json_dumps(indent=2)
+ return jws.JWS.sign(jobj, **cast(Mapping[str, Any], kwargs)).json_dumps(indent=2)
@classmethod
def _check_response(cls, response: requests.Response,
diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py
index b337e7697..eb6672926 100644
--- a/acme/acme/crypto_util.py
+++ b/acme/acme/crypto_util.py
@@ -278,7 +278,7 @@ def _pyopenssl_cert_or_req_san(cert_or_req: Union[crypto.X509, crypto.X509Req])
:type cert_or_req: `OpenSSL.crypto.X509` or `OpenSSL.crypto.X509Req`.
:returns: A list of Subject Alternative Names that is DNS.
- :rtype: `list` of `unicode`
+ :rtype: `list` of `str`
"""
# This function finds SANs with dns name
@@ -300,7 +300,7 @@ def _pyopenssl_cert_or_req_san_ip(cert_or_req: Union[crypto.X509, crypto.X509Req
:type cert_or_req: `OpenSSL.crypto.X509` or `OpenSSL.crypto.X509Req`.
:returns: A list of Subject Alternative Names that are IP Addresses.
- :rtype: `list` of `unicode`. note that this returns as string, not IPaddress object
+ :rtype: `list` of `str`. note that this returns as string, not IPaddress object
"""
@@ -320,7 +320,7 @@ def _pyopenssl_extract_san_list_raw(cert_or_req: Union[crypto.X509, crypto.X509R
:type cert_or_req: `OpenSSL.crypto.X509` or `OpenSSL.crypto.X509Req`.
:returns: raw san strings, parsed byte as utf-8
- :rtype: `list` of `unicode`
+ :rtype: `list` of `str`
"""
# This function finds SANs by dumping the certificate/CSR to text and
@@ -352,7 +352,7 @@ def gen_ss_cert(key: crypto.PKey, domains: Optional[List[str]] = None,
) -> crypto.X509:
"""Generate new self-signed certificate.
- :type domains: `list` of `unicode`
+ :type domains: `list` of `str`
:param OpenSSL.crypto.PKey key:
:param bool force_san:
:param extensions: List of additional extensions to include in the cert.
@@ -410,7 +410,8 @@ def gen_ss_cert(key: crypto.PKey, domains: Optional[List[str]] = None,
return cert
-def dump_pyopenssl_chain(chain: List[crypto.X509], filetype: int = crypto.FILETYPE_PEM) -> bytes:
+def dump_pyopenssl_chain(chain: Union[List[jose.ComparableX509], List[crypto.X509]],
+ filetype: int = crypto.FILETYPE_PEM) -> bytes:
"""Dump certificate chain into a bundle.
:param list chain: List of `OpenSSL.crypto.X509` (or wrapped in
@@ -425,6 +426,8 @@ def dump_pyopenssl_chain(chain: List[crypto.X509], filetype: int = crypto.FILETY
def _dump_cert(cert: Union[jose.ComparableX509, crypto.X509]) -> bytes:
if isinstance(cert, jose.ComparableX509):
+ if isinstance(cert.wrapped, crypto.X509Req):
+ raise errors.Error("Unexpected CSR provided.") # pragma: no cover
cert = cert.wrapped
return crypto.dump_certificate(filetype, cert)
diff --git a/acme/acme/fields.py b/acme/acme/fields.py
index b15489020..191231df2 100644
--- a/acme/acme/fields.py
+++ b/acme/acme/fields.py
@@ -56,8 +56,8 @@ class Resource(jose.Field):
def __init__(self, resource_type: str, *args: Any, **kwargs: Any) -> None:
self.resource_type = resource_type
- super().__init__(
- 'resource', default=resource_type, *args, **kwargs)
+ kwargs['default'] = resource_type
+ super().__init__('resource', *args, **kwargs)
def decode(self, value: Any) -> Any:
if value != self.resource_type:
@@ -65,3 +65,18 @@ class Resource(jose.Field):
'Wrong resource type: {0} instead of {1}'.format(
value, self.resource_type))
return value
+
+
+def fixed(json_name: str, value: Any) -> Any:
+ """Generates a type-friendly Fixed field."""
+ return Fixed(json_name, value)
+
+
+def rfc3339(json_name: str, omitempty: bool = False) -> Any:
+ """Generates a type-friendly RFC3339 field."""
+ return RFC3339Field(json_name, omitempty=omitempty)
+
+
+def resource(resource_type: str) -> Any:
+ """Generates a type-friendly Resource field."""
+ return Resource(resource_type)
diff --git a/acme/acme/jws.py b/acme/acme/jws.py
index bde1bb590..2a9627c6d 100644
--- a/acme/acme/jws.py
+++ b/acme/acme/jws.py
@@ -12,14 +12,14 @@ import josepy as jose
class Header(jose.Header):
"""ACME-specific JOSE Header. Implements nonce, kid, and url.
"""
- nonce = jose.Field('nonce', omitempty=True, encoder=jose.encode_b64jose)
- kid = jose.Field('kid', omitempty=True)
- url = jose.Field('url', omitempty=True)
+ nonce: Optional[bytes] = jose.field('nonce', omitempty=True, encoder=jose.encode_b64jose)
+ kid: Optional[str] = jose.field('kid', omitempty=True)
+ url: Optional[str] = jose.field('url', omitempty=True)
# Mypy does not understand the josepy magic happening here, and falsely claims
# that nonce is redefined. Let's ignore the type check here.
- @nonce.decoder # type: ignore
- def nonce(value: str) -> bytes: # pylint: disable=no-self-argument,missing-function-docstring
+ @nonce.decoder # type: ignore[no-redef,union-attr]
+ def nonce(value: str) -> bytes: # type: ignore[misc] # pylint: disable=no-self-argument,missing-function-docstring
try:
return jose.decode_b64jose(value)
except jose.DeserializationError as error:
@@ -29,12 +29,12 @@ class Header(jose.Header):
class Signature(jose.Signature):
"""ACME-specific Signature. Uses ACME-specific Header for customer fields."""
- __slots__ = jose.Signature._orig_slots # pylint: disable=no-member
+ __slots__ = jose.Signature._orig_slots # type: ignore[attr-defined] # pylint: disable=protected-access,no-member
# TODO: decoder/encoder should accept cls? Otherwise, subclassing
# JSONObjectWithFields is tricky...
header_cls = Header
- header = jose.Field(
+ header: Header = jose.field(
'header', omitempty=True, default=header_cls(),
decoder=header_cls.from_json)
@@ -44,10 +44,10 @@ class Signature(jose.Signature):
class JWS(jose.JWS):
"""ACME-specific JWS. Includes none, url, and kid in protected header."""
signature_cls = Signature
- __slots__ = jose.JWS._orig_slots
+ __slots__ = jose.JWS._orig_slots # type: ignore[attr-defined] # pylint: disable=protected-access
@classmethod
- # pylint: disable=arguments-differ
+ # type: ignore[override] # pylint: disable=arguments-differ
def sign(cls, payload: bytes, key: jose.JWK, alg: jose.JWASignature, nonce: Optional[bytes],
url: Optional[str] = None, kid: Optional[str] = None) -> jose.JWS:
# Per ACME spec, jwk and kid are mutually exclusive, so only include a
diff --git a/acme/acme/messages.py b/acme/acme/messages.py
index 80dacb674..c02a600da 100644
--- a/acme/acme/messages.py
+++ b/acme/acme/messages.py
@@ -1,4 +1,5 @@
"""ACME protocol messages."""
+import datetime
from collections.abc import Hashable
import json
from typing import Any
@@ -7,9 +8,12 @@ from typing import Iterator
from typing import List
from typing import Mapping
from typing import MutableMapping
+from typing import Optional
from typing import Tuple
from typing import Type
-from typing import Optional
+from typing import TYPE_CHECKING
+from typing import TypeVar
+from typing import Union
import josepy as jose
@@ -20,6 +24,11 @@ from acme import jws
from acme import util
from acme.mixins import ResourceMixin
+if TYPE_CHECKING:
+ from typing_extensions import Protocol # pragma: no cover
+else:
+ Protocol = object
+
OLD_ERROR_PREFIX = "urn:acme:error:"
ERROR_PREFIX = "urn:ietf:params:acme:error:"
@@ -75,20 +84,20 @@ class Error(jose.JSONObjectWithFields, errors.Error):
https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00
- :ivar unicode typ:
- :ivar unicode title:
- :ivar unicode detail:
+ :ivar str typ:
+ :ivar str title:
+ :ivar str detail:
"""
- typ = jose.Field('type', omitempty=True, default='about:blank')
- title = jose.Field('title', omitempty=True)
- detail = jose.Field('detail', omitempty=True)
+ typ: str = jose.field('type', omitempty=True, default='about:blank')
+ title: str = jose.field('title', omitempty=True)
+ detail: str = jose.field('detail', omitempty=True)
@classmethod
def with_code(cls, code: str, **kwargs: Any) -> 'Error':
"""Create an Error instance with an ACME Error code.
- :unicode code: An ACME error code, like 'dnssec'.
+ :str code: An ACME error code, like 'dnssec'.
:kwargs: kwargs to pass to Error.
"""
@@ -98,14 +107,14 @@ class Error(jose.JSONObjectWithFields, errors.Error):
typ = ERROR_PREFIX + code
# Mypy will not understand that the Error constructor accepts a named argument
# "typ" because of josepy magic. Let's ignore the type check here.
- return cls(typ=typ, **kwargs) # type: ignore
+ return cls(typ=typ, **kwargs)
@property
def description(self) -> Optional[str]:
"""Hardcoded error description based on its type.
:returns: Description if standard ACME error or ``None``.
- :rtype: unicode
+ :rtype: str
"""
return ERROR_TYPE_DESCRIPTIONS.get(self.typ)
@@ -117,7 +126,7 @@ class Error(jose.JSONObjectWithFields, errors.Error):
Basically self.typ without the ERROR_PREFIX.
:returns: error code if standard ACME code or ``None``.
- :rtype: unicode
+ :rtype: str
"""
code = str(self.typ).rsplit(':', maxsplit=1)[-1]
@@ -164,7 +173,7 @@ class _Constant(jose.JSONDeSerializable, Hashable):
class Status(_Constant):
"""ACME "status" field."""
- POSSIBLE_NAMES: Dict[str, 'Status'] = {}
+ POSSIBLE_NAMES: Dict[str, _Constant] = {}
STATUS_UNKNOWN = Status('unknown')
@@ -179,7 +188,7 @@ STATUS_DEACTIVATED = Status('deactivated')
class IdentifierType(_Constant):
"""ACME identifier type."""
- POSSIBLE_NAMES: Dict[str, 'IdentifierType'] = {}
+ POSSIBLE_NAMES: Dict[str, _Constant] = {}
IDENTIFIER_FQDN = IdentifierType('dns') # IdentifierDNS in Boulder
@@ -190,25 +199,35 @@ class Identifier(jose.JSONObjectWithFields):
"""ACME identifier.
:ivar IdentifierType typ:
- :ivar unicode value:
+ :ivar str value:
+
+ """
+ typ: IdentifierType = jose.field('type', decoder=IdentifierType.from_json)
+ value: str = jose.field('value')
+
+class HasResourceType(Protocol):
"""
- typ = jose.Field('type', decoder=IdentifierType.from_json)
- value = jose.Field('value')
+ Represents a class with a resource_type class parameter of type string.
+ """
+ resource_type: str = NotImplemented
+
+
+GenericHasResourceType = TypeVar("GenericHasResourceType", bound=HasResourceType)
class Directory(jose.JSONDeSerializable):
"""Directory."""
- _REGISTERED_TYPES: Dict[str, Type['Directory']] = {}
+ _REGISTERED_TYPES: Dict[str, Type[HasResourceType]] = {}
class Meta(jose.JSONObjectWithFields):
"""Directory Meta."""
- _terms_of_service = jose.Field('terms-of-service', omitempty=True)
- _terms_of_service_v2 = jose.Field('termsOfService', omitempty=True)
- website = jose.Field('website', omitempty=True)
- caa_identities = jose.Field('caaIdentities', omitempty=True)
- external_account_required = jose.Field('externalAccountRequired', omitempty=True)
+ _terms_of_service: str = jose.field('terms-of-service', omitempty=True)
+ _terms_of_service_v2: str = jose.field('termsOfService', omitempty=True)
+ website: str = jose.field('website', omitempty=True)
+ caa_identities: List[str] = jose.field('caaIdentities', omitempty=True)
+ external_account_required: bool = jose.field('externalAccountRequired', omitempty=True)
def __init__(self, **kwargs: Any) -> None:
kwargs = {self._internal_name(k): v for k, v in kwargs.items()}
@@ -229,11 +248,14 @@ class Directory(jose.JSONDeSerializable):
return '_' + name if name == 'terms_of_service' else name
@classmethod
- def _canon_key(cls, key: str) -> str:
- return getattr(key, 'resource_type', key)
+ def _canon_key(cls, key: Union[str, HasResourceType, Type[HasResourceType]]) -> str:
+ if isinstance(key, str):
+ return key
+ return key.resource_type
@classmethod
- def register(cls, resource_body_cls: Type['Directory']) -> Type['Directory']:
+ def register(cls,
+ resource_body_cls: Type[GenericHasResourceType]) -> Type[GenericHasResourceType]:
"""Register resource."""
resource_type = resource_body_cls.resource_type
assert resource_type not in cls._REGISTERED_TYPES
@@ -252,7 +274,7 @@ class Directory(jose.JSONDeSerializable):
except KeyError as error:
raise AttributeError(str(error))
- def __getitem__(self, name: str) -> Any:
+ def __getitem__(self, name: Union[str, HasResourceType, Type[HasResourceType]]) -> Any:
try:
return self._jobj[self._canon_key(name)]
except KeyError:
@@ -273,16 +295,16 @@ class Resource(jose.JSONObjectWithFields):
:ivar acme.messages.ResourceBody body: Resource body.
"""
- body = jose.Field('body')
+ body: "ResourceBody" = jose.field('body')
class ResourceWithURI(Resource):
"""ACME Resource with URI.
- :ivar unicode ~.uri: Location of the resource.
+ :ivar str uri: Location of the resource.
"""
- uri = jose.Field('uri') # no ChallengeResource.uri
+ uri: str = jose.field('uri') # no ChallengeResource.uri
class ResourceBody(jose.JSONObjectWithFields):
@@ -308,35 +330,40 @@ class ExternalAccountBinding:
return eab.to_partial_json()
+GenericRegistration = TypeVar('GenericRegistration', bound='Registration')
+
+
class Registration(ResourceBody):
"""Registration Resource Body.
- :ivar josepy.jwk.JWK key: Public key.
+ :ivar jose.JWK key: Public key.
:ivar tuple contact: Contact information following ACME spec,
- `tuple` of `unicode`.
- :ivar unicode agreement:
+ `tuple` of `str`.
+ :ivar str agreement:
"""
# on new-reg key server ignores 'key' and populates it based on
# JWS.signature.combined.jwk
- key = jose.Field('key', omitempty=True, decoder=jose.JWK.from_json)
+ key: jose.JWK = jose.field('key', omitempty=True, decoder=jose.JWK.from_json)
# Contact field implements special behavior to allow messages that clear existing
# contacts while not expecting the `contact` field when loading from json.
# This is implemented in the constructor and *_json methods.
- contact = jose.Field('contact', omitempty=True, default=())
- agreement = jose.Field('agreement', omitempty=True)
- status = jose.Field('status', omitempty=True)
- terms_of_service_agreed = jose.Field('termsOfServiceAgreed', omitempty=True)
- only_return_existing = jose.Field('onlyReturnExisting', omitempty=True)
- external_account_binding = jose.Field('externalAccountBinding', omitempty=True)
+ contact: Tuple[str, ...] = jose.field('contact', omitempty=True, default=())
+ agreement: str = jose.field('agreement', omitempty=True)
+ status: Status = jose.field('status', omitempty=True)
+ terms_of_service_agreed: bool = jose.field('termsOfServiceAgreed', omitempty=True)
+ only_return_existing: bool = jose.field('onlyReturnExisting', omitempty=True)
+ external_account_binding: Dict[str, Any] = jose.field('externalAccountBinding',
+ omitempty=True)
phone_prefix = 'tel:'
email_prefix = 'mailto:'
@classmethod
- def from_data(cls, phone: Optional[str] = None, email: Optional[str] = None,
+ def from_data(cls: Type[GenericRegistration], phone: Optional[str] = None,
+ email: Optional[str] = None,
external_account_binding: Optional[Dict[str, Any]] = None,
- **kwargs: Any) -> 'Registration':
+ **kwargs: Any) -> GenericRegistration:
"""
Create registration resource from contact details.
@@ -419,26 +446,26 @@ class Registration(ResourceBody):
class NewRegistration(ResourceMixin, Registration):
"""New registration."""
resource_type = 'new-reg'
- resource = fields.Resource(resource_type)
+ resource: str = fields.resource(resource_type)
class UpdateRegistration(ResourceMixin, Registration):
"""Update registration."""
resource_type = 'reg'
- resource = fields.Resource(resource_type)
+ resource: str = fields.resource(resource_type)
class RegistrationResource(ResourceWithURI):
"""Registration Resource.
:ivar acme.messages.Registration body:
- :ivar unicode new_authzr_uri: Deprecated. Do not use.
- :ivar unicode terms_of_service: URL for the CA TOS.
+ :ivar str new_authzr_uri: Deprecated. Do not use.
+ :ivar str terms_of_service: URL for the CA TOS.
"""
- body = jose.Field('body', decoder=Registration.from_json)
- new_authzr_uri = jose.Field('new_authzr_uri', omitempty=True)
- terms_of_service = jose.Field('terms_of_service', omitempty=True)
+ body: Registration = jose.field('body', decoder=Registration.from_json)
+ new_authzr_uri: str = jose.field('new_authzr_uri', omitempty=True)
+ terms_of_service: str = jose.field('terms_of_service', omitempty=True)
class ChallengeBody(ResourceBody):
@@ -463,12 +490,12 @@ class ChallengeBody(ResourceBody):
# challenge object supports either one, but should be accessed through the
# name "uri". In Client.answer_challenge, whichever one is set will be
# used.
- _uri = jose.Field('uri', omitempty=True, default=None)
- _url = jose.Field('url', omitempty=True, default=None)
- status = jose.Field('status', decoder=Status.from_json,
+ _uri: str = jose.field('uri', omitempty=True, default=None)
+ _url: str = jose.field('url', omitempty=True, default=None)
+ status: Status = jose.field('status', decoder=Status.from_json,
omitempty=True, default=STATUS_PENDING)
- validated = fields.RFC3339Field('validated', omitempty=True)
- error = jose.Field('error', decoder=Error.from_json,
+ validated: datetime.datetime = fields.rfc3339('validated', omitempty=True)
+ error: Error = jose.field('error', decoder=Error.from_json,
omitempty=True, default=None)
def __init__(self, **kwargs: Any) -> None:
@@ -511,16 +538,16 @@ class ChallengeResource(Resource):
"""Challenge Resource.
:ivar acme.messages.ChallengeBody body:
- :ivar unicode authzr_uri: URI found in the 'up' ``Link`` header.
+ :ivar str authzr_uri: URI found in the 'up' ``Link`` header.
"""
- body = jose.Field('body', decoder=ChallengeBody.from_json)
- authzr_uri = jose.Field('authzr_uri')
+ body: ChallengeBody = jose.field('body', decoder=ChallengeBody.from_json)
+ authzr_uri: str = jose.field('authzr_uri')
@property
def uri(self) -> str:
"""The URL of the challenge body."""
- return self.body.uri
+ return self.body.uri # pylint: disable=no-member
class Authorization(ResourceBody):
@@ -534,26 +561,26 @@ class Authorization(ResourceBody):
:ivar datetime.datetime expires:
"""
- identifier = jose.Field('identifier', decoder=Identifier.from_json, omitempty=True)
- challenges = jose.Field('challenges', omitempty=True)
- combinations = jose.Field('combinations', omitempty=True)
+ identifier: Identifier = jose.field('identifier', decoder=Identifier.from_json, omitempty=True)
+ challenges: List[ChallengeBody] = jose.field('challenges', omitempty=True)
+ combinations: Tuple[Tuple[int, ...], ...] = jose.field('combinations', omitempty=True)
- status = jose.Field('status', omitempty=True, decoder=Status.from_json)
+ status: Status = jose.field('status', omitempty=True, decoder=Status.from_json)
# TODO: 'expires' is allowed for Authorization Resources in
# general, but for Key Authorization '[t]he "expires" field MUST
# be absent'... then acme-spec gives example with 'expires'
# present... That's confusing!
- expires = fields.RFC3339Field('expires', omitempty=True)
- wildcard = jose.Field('wildcard', omitempty=True)
+ expires: datetime.datetime = fields.rfc3339('expires', omitempty=True)
+ wildcard: bool = jose.field('wildcard', omitempty=True)
# Mypy does not understand the josepy magic happening here, and falsely claims
# that challenge is redefined. Let's ignore the type check here.
@challenges.decoder # type: ignore
- def challenges(value: List[Mapping[str, Any]]) -> Tuple[ChallengeBody, ...]: # pylint: disable=no-self-argument,missing-function-docstring
+ def challenges(value: List[Dict[str, Any]]) -> Tuple[ChallengeBody, ...]: # type: ignore[misc] # pylint: disable=no-self-argument,missing-function-docstring
return tuple(ChallengeBody.from_json(chall) for chall in value)
@property
- def resolved_combinations(self) -> Tuple[Tuple[Dict[str, Any], ...], ...]:
+ def resolved_combinations(self) -> Tuple[Tuple[ChallengeBody, ...], ...]:
"""Combinations with challenges instead of indices."""
return tuple(tuple(self.challenges[idx] for idx in combo)
for combo in self.combinations) # pylint: disable=not-an-iterable
@@ -563,37 +590,37 @@ class Authorization(ResourceBody):
class NewAuthorization(ResourceMixin, Authorization):
"""New authorization."""
resource_type = 'new-authz'
- resource = fields.Resource(resource_type)
+ resource: str = fields.resource(resource_type)
class UpdateAuthorization(ResourceMixin, Authorization):
"""Update authorization."""
resource_type = 'authz'
- resource = fields.Resource(resource_type)
+ resource: str = fields.resource(resource_type)
class AuthorizationResource(ResourceWithURI):
"""Authorization Resource.
:ivar acme.messages.Authorization body:
- :ivar unicode new_cert_uri: Deprecated. Do not use.
+ :ivar str new_cert_uri: Deprecated. Do not use.
"""
- body = jose.Field('body', decoder=Authorization.from_json)
- new_cert_uri = jose.Field('new_cert_uri', omitempty=True)
+ body: Authorization = jose.field('body', decoder=Authorization.from_json)
+ new_cert_uri: str = jose.field('new_cert_uri', omitempty=True)
@Directory.register
class CertificateRequest(ResourceMixin, jose.JSONObjectWithFields):
"""ACME new-cert request.
- :ivar josepy.util.ComparableX509 csr:
+ :ivar jose.ComparableX509 csr:
`OpenSSL.crypto.X509Req` wrapped in `.ComparableX509`
"""
resource_type = 'new-cert'
- resource = fields.Resource(resource_type)
- csr = jose.Field('csr', decoder=jose.decode_csr, encoder=jose.encode_csr)
+ resource: str = fields.resource(resource_type)
+ csr: jose.ComparableX509 = jose.field('csr', decoder=jose.decode_csr, encoder=jose.encode_csr)
class CertificateResource(ResourceWithURI):
@@ -601,27 +628,27 @@ class CertificateResource(ResourceWithURI):
:ivar josepy.util.ComparableX509 body:
`OpenSSL.crypto.X509` wrapped in `.ComparableX509`
- :ivar unicode cert_chain_uri: URI found in the 'up' ``Link`` header
+ :ivar str cert_chain_uri: URI found in the 'up' ``Link`` header
:ivar tuple authzrs: `tuple` of `AuthorizationResource`.
"""
- cert_chain_uri = jose.Field('cert_chain_uri')
- authzrs = jose.Field('authzrs')
+ cert_chain_uri: str = jose.field('cert_chain_uri')
+ authzrs: Tuple[AuthorizationResource, ...] = jose.field('authzrs')
@Directory.register
class Revocation(ResourceMixin, jose.JSONObjectWithFields):
"""Revocation message.
- :ivar .ComparableX509 certificate: `OpenSSL.crypto.X509` wrapped in
- `.ComparableX509`
+ :ivar jose.ComparableX509 certificate: `OpenSSL.crypto.X509` wrapped in
+ `jose.ComparableX509`
"""
resource_type = 'revoke-cert'
- resource = fields.Resource(resource_type)
- certificate = jose.Field(
+ resource: str = fields.resource(resource_type)
+ certificate: jose.ComparableX509 = jose.field(
'certificate', decoder=jose.decode_cert, encoder=jose.encode_cert)
- reason = jose.Field('reason')
+ reason: int = jose.field('reason')
class Order(ResourceBody):
@@ -638,19 +665,18 @@ class Order(ResourceBody):
:ivar datetime.datetime expires: When the order expires.
:ivar ~.Error error: Any error that occurred during finalization, if applicable.
"""
- identifiers = jose.Field('identifiers', omitempty=True)
- status = jose.Field('status', decoder=Status.from_json,
- omitempty=True)
- authorizations = jose.Field('authorizations', omitempty=True)
- certificate = jose.Field('certificate', omitempty=True)
- finalize = jose.Field('finalize', omitempty=True)
- expires = fields.RFC3339Field('expires', omitempty=True)
- error = jose.Field('error', omitempty=True, decoder=Error.from_json)
+ identifiers: List[Identifier] = jose.field('identifiers', omitempty=True)
+ status: Status = jose.field('status', decoder=Status.from_json, omitempty=True)
+ authorizations: List[str] = jose.field('authorizations', omitempty=True)
+ certificate: str = jose.field('certificate', omitempty=True)
+ finalize: str = jose.field('finalize', omitempty=True)
+ expires: datetime.datetime = fields.rfc3339('expires', omitempty=True)
+ error: Error = jose.field('error', omitempty=True, decoder=Error.from_json)
# Mypy does not understand the josepy magic happening here, and falsely claims
# that identifiers is redefined. Let's ignore the type check here.
@identifiers.decoder # type: ignore
- def identifiers(value: List[Mapping[str, Any]]) -> Tuple[Identifier, ...]: # pylint: disable=no-self-argument,missing-function-docstring
+ def identifiers(value: List[Dict[str, Any]]) -> Tuple[Identifier, ...]: # type: ignore[misc] # pylint: disable=no-self-argument,missing-function-docstring
return tuple(Identifier.from_json(identifier) for identifier in value)
@@ -658,7 +684,7 @@ class OrderResource(ResourceWithURI):
"""Order Resource.
:ivar acme.messages.Order body:
- :ivar str csr_pem: The CSR this Order will be finalized with.
+ :ivar bytes csr_pem: The CSR this Order will be finalized with.
:ivar authorizations: Fully-fetched AuthorizationResource objects.
:vartype authorizations: `list` of `acme.messages.AuthorizationResource`
:ivar str fullchain_pem: The fetched contents of the certificate URL
@@ -668,11 +694,13 @@ class OrderResource(ResourceWithURI):
finalization.
:vartype alternative_fullchains_pem: `list` of `str`
"""
- body = jose.Field('body', decoder=Order.from_json)
- csr_pem = jose.Field('csr_pem', omitempty=True)
- authorizations = jose.Field('authorizations')
- fullchain_pem = jose.Field('fullchain_pem', omitempty=True)
- alternative_fullchains_pem = jose.Field('alternative_fullchains_pem', omitempty=True)
+ body: Order = jose.field('body', decoder=Order.from_json)
+ csr_pem: bytes = jose.field('csr_pem', omitempty=True)
+ authorizations: List[AuthorizationResource] = jose.field('authorizations')
+ fullchain_pem: str = jose.field('fullchain_pem', omitempty=True)
+ alternative_fullchains_pem: List[str] = jose.field('alternative_fullchains_pem',
+ omitempty=True)
+
@Directory.register
class NewOrder(Order):
diff --git a/acme/acme/standalone.py b/acme/acme/standalone.py
index 5dfb27136..f2df276a4 100644
--- a/acme/acme/standalone.py
+++ b/acme/acme/standalone.py
@@ -8,6 +8,7 @@ import socket
import socketserver
import threading
from typing import Any
+from typing import cast
from typing import List
from typing import Mapping
from typing import Optional
@@ -39,10 +40,10 @@ class TLSServer(socketserver.TCPServer):
super().__init__(*args, **kwargs)
def _wrap_sock(self) -> None:
- self.socket = crypto_util.SSLSocket(
+ self.socket = cast(socket.socket, crypto_util.SSLSocket(
self.socket, cert_selection=self._cert_selection,
alpn_selection=getattr(self, '_alpn_selection', None),
- method=self.method)
+ method=self.method))
def _cert_selection(self, connection: SSL.Connection
) -> Tuple[crypto.PKey, crypto.X509]: # pragma: no cover
diff --git a/acme/setup.py b/acme/setup.py
index e5d822202..fb97eb6ad 100644
--- a/acme/setup.py
+++ b/acme/setup.py
@@ -7,7 +7,7 @@ version = '1.23.0.dev0'
install_requires = [
'cryptography>=2.5.0',
- 'josepy>=1.9.0',
+ 'josepy>=1.10.0',
'PyOpenSSL>=17.3.0',
'pyrfc3339',
'pytz',
@@ -24,6 +24,7 @@ docs_extras = [
test_extras = [
'pytest',
'pytest-xdist',
+ 'typing-extensions',
]
setup(
diff --git a/acme/tests/fields_test.py b/acme/tests/fields_test.py
index 69dde8b89..4cc167f9c 100644
--- a/acme/tests/fields_test.py
+++ b/acme/tests/fields_test.py
@@ -10,8 +10,8 @@ class FixedTest(unittest.TestCase):
"""Tests for acme.fields.Fixed."""
def setUp(self):
- from acme.fields import Fixed
- self.field = Fixed('name', 'x')
+ from acme.fields import fixed
+ self.field = fixed('name', 'x')
def test_decode(self):
self.assertEqual('x', self.field.decode('x'))
diff --git a/certbot-apache/certbot_apache/_internal/configurator.py b/certbot-apache/certbot_apache/_internal/configurator.py
index 73b6a1e1b..9b814f60d 100644
--- a/certbot-apache/certbot_apache/_internal/configurator.py
+++ b/certbot-apache/certbot_apache/_internal/configurator.py
@@ -22,11 +22,9 @@ from typing import Type
from typing import Union
from acme import challenges
-from acme.challenges import Challenge
from certbot import achallenges
from certbot import errors
from certbot import util
-from certbot.achallenges import KeyAuthorizationAnnotatedChallenge
from certbot.compat import filesystem
from certbot.compat import os
from certbot.display import util as display_util
@@ -240,7 +238,7 @@ class ApacheConfigurator(common.Configurator):
# Add name_server association dict
self.assoc: Dict[str, obj.VirtualHost] = {}
# Outstanding challenges
- self._chall_out: Set[KeyAuthorizationAnnotatedChallenge] = set()
+ self._chall_out: Set[achallenges.AnnotatedChallenge] = set()
# List of vhosts configured per wildcard domain on this run.
# used by deploy_cert() and enhance()
self._wildcard_vhosts: Dict[str, List[obj.VirtualHost]] = {}
@@ -2532,9 +2530,8 @@ class ApacheConfigurator(common.Configurator):
"""Return list of challenge preferences."""
return [challenges.HTTP01]
- def perform(
- self, achalls: List[KeyAuthorizationAnnotatedChallenge]
- ) -> List[Challenge]:
+ def perform(self, achalls: List[achallenges.AnnotatedChallenge]
+ ) -> List[challenges.ChallengeResponse]:
"""Perform the configuration related challenge.
This function currently assumes all challenges will be fulfilled.
@@ -2543,10 +2540,13 @@ class ApacheConfigurator(common.Configurator):
"""
self._chall_out.update(achalls)
- responses: List[Optional[Challenge]] = [None] * len(achalls)
+ responses: List[Optional[challenges.ChallengeResponse]] = [None] * len(achalls)
http_doer = http_01.ApacheHttp01(self)
for i, achall in enumerate(achalls):
+ if not isinstance(achall, achallenges.KeyAuthorizationAnnotatedChallenge):
+ raise errors.Error("Challenge should be an instance " # pragma: no cover
+ "of KeyAuthorizationAnnotatedChallenge")
# Currently also have chall_doer hold associated index of the
# challenge. This helps to put all of the responses back together
# when they are all complete.
@@ -2560,18 +2560,17 @@ class ApacheConfigurator(common.Configurator):
self.restart()
# TODO: Remove this dirty hack. We need to determine a reliable way
- # of identifying when the new configuration is being used.
+ # of identifying when the new configuration is being used.
time.sleep(3)
self._update_responses(responses, http_response, http_doer)
- # We assume all challenges has been fulfilled as described in the function documentation.
- return cast(List[Challenge], responses)
+ return [response for response in responses if response]
def _update_responses(
self,
- responses: List[Optional[challenges.HTTP01Response]],
- chall_response: List[Challenge],
+ responses: List[Optional[challenges.ChallengeResponse]],
+ chall_response: List[challenges.KeyAuthorizationChallengeResponse],
chall_doer: http_01.ApacheHttp01
) -> None:
# Go through all of the challenges and assign them to the proper
@@ -2580,7 +2579,7 @@ class ApacheConfigurator(common.Configurator):
for i, resp in enumerate(chall_response):
responses[chall_doer.indices[i]] = resp
- def cleanup(self, achalls: List[KeyAuthorizationAnnotatedChallenge]) -> None:
+ def cleanup(self, achalls: List[achallenges.AnnotatedChallenge]) -> None:
"""Revert all challenges."""
self._chall_out.difference_update(achalls)
diff --git a/certbot-apache/certbot_apache/_internal/http_01.py b/certbot-apache/certbot_apache/_internal/http_01.py
index 2fe981720..eed849dbe 100644
--- a/certbot-apache/certbot_apache/_internal/http_01.py
+++ b/certbot-apache/certbot_apache/_internal/http_01.py
@@ -1,12 +1,11 @@
"""A class that performs HTTP-01 challenges for Apache"""
import errno
import logging
-from typing import Any
from typing import List
from typing import Set
from typing import TYPE_CHECKING
-from acme.challenges import HTTP01Response
+from acme.challenges import KeyAuthorizationChallengeResponse
from certbot import errors
from certbot.achallenges import KeyAuthorizationAnnotatedChallenge
from certbot.compat import filesystem
@@ -67,7 +66,7 @@ class ApacheHttp01(common.ChallengePerformer):
"http_challenges")
self.moded_vhosts: Set[VirtualHost] = set()
- def perform(self) -> List[KeyAuthorizationAnnotatedChallenge]:
+ def perform(self) -> List[KeyAuthorizationChallengeResponse]:
"""Perform all HTTP-01 challenges."""
if not self.achalls:
return []
@@ -182,7 +181,7 @@ class ApacheHttp01(common.ChallengePerformer):
"""Return all VirtualHost objects with no ServerName"""
return [vh for vh in self.configurator.vhosts if vh.name is None]
- def _set_up_challenges(self) -> List[HTTP01Response]:
+ def _set_up_challenges(self) -> List[KeyAuthorizationChallengeResponse]:
if not os.path.isdir(self.challenge_dir):
old_umask = filesystem.umask(0o022)
try:
@@ -200,9 +199,8 @@ class ApacheHttp01(common.ChallengePerformer):
return responses
- def _set_up_challenge(self, achall: KeyAuthorizationAnnotatedChallenge) -> HTTP01Response:
- response: HTTP01Response
- validation: Any
+ def _set_up_challenge(self, achall: KeyAuthorizationAnnotatedChallenge
+ ) -> KeyAuthorizationChallengeResponse:
response, validation = achall.response_and_validation()
name: str = os.path.join(self.challenge_dir, achall.chall.encode("token"))
diff --git a/certbot-ci/certbot_integration_tests/utils/misc.py b/certbot-ci/certbot_integration_tests/utils/misc.py
index 9143804f9..a36b348e0 100644
--- a/certbot-ci/certbot_integration_tests/utils/misc.py
+++ b/certbot-ci/certbot_integration_tests/utils/misc.py
@@ -48,7 +48,8 @@ def _suppress_x509_verification_warnings() -> None:
# Handle old versions of request with vendorized urllib3
# pylint: disable=no-member
from requests.packages.urllib3.exceptions import InsecureRequestWarning
- requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+ requests.packages.urllib3.disable_warnings( # type: ignore[attr-defined]
+ InsecureRequestWarning)
def check_until_timeout(url: str, attempts: int = 30) -> None:
diff --git a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py
index 1b27a2195..26b7660ab 100644
--- a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py
+++ b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py
@@ -106,7 +106,7 @@ def test_authenticator(plugin: common.Proxy, config: str, temp_dir: str) -> bool
def _create_achalls(plugin: common.Proxy) -> List[achallenges.AnnotatedChallenge]:
"""Returns a list of annotated challenges to test on plugin"""
- achalls = []
+ achalls: List[achallenges.AnnotatedChallenge] = []
names = plugin.get_testable_domain_names()
for domain in names:
prefs = plugin.get_chall_pref(domain)
diff --git a/certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py b/certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py
index d3fdd5e8c..8cf6d9966 100644
--- a/certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py
+++ b/certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py
@@ -138,7 +138,7 @@ class _RFC2136Client:
except Exception as e:
raise errors.PluginError('Encountered error adding TXT record: {0}'
.format(e))
- rcode = response.rcode()
+ rcode = response.rcode() # type: ignore[attr-defined]
if rcode == dns.rcode.NOERROR:
logger.debug('Successfully added TXT record %s', record_name)
@@ -173,7 +173,7 @@ class _RFC2136Client:
except Exception as e:
raise errors.PluginError('Encountered error deleting TXT record: {0}'
.format(e))
- rcode = response.rcode()
+ rcode = response.rcode() # type: ignore[attr-defined]
if rcode == dns.rcode.NOERROR:
logger.debug('Successfully deleted TXT record %s', record_name)
@@ -223,11 +223,13 @@ class _RFC2136Client:
except (OSError, dns.exception.Timeout) as e:
logger.debug('TCP query failed, fallback to UDP: %s', e)
response = dns.query.udp(request, self.server, self._default_timeout, self.port)
- rcode = response.rcode()
+ rcode = response.rcode() # type: ignore[attr-defined]
# Authoritative Answer bit should be set
- if (rcode == dns.rcode.NOERROR and response.get_rrset(response.answer,
- domain, dns.rdataclass.IN, dns.rdatatype.SOA) and response.flags & dns.flags.AA):
+ if (rcode == dns.rcode.NOERROR
+ and response.get_rrset(response.answer, # type: ignore[attr-defined]
+ domain, dns.rdataclass.IN, dns.rdatatype.SOA)
+ and response.flags & dns.flags.AA):
logger.debug('Received authoritative SOA response for %s', domain_name)
return True
diff --git a/certbot-nginx/certbot_nginx/_internal/configurator.py b/certbot-nginx/certbot_nginx/_internal/configurator.py
index fb819f194..39784110c 100644
--- a/certbot-nginx/certbot_nginx/_internal/configurator.py
+++ b/certbot-nginx/certbot_nginx/_internal/configurator.py
@@ -1180,7 +1180,7 @@ class NginxConfigurator(common.Configurator):
# Entry point in main.py for performing challenges
def perform(self, achalls: List[achallenges.AnnotatedChallenge]
- ) -> List[challenges.HTTP01Response]:
+ ) -> List[challenges.ChallengeResponse]:
"""Perform the configuration related challenge.
This function currently assumes all challenges will be fulfilled.
@@ -1189,13 +1189,16 @@ class NginxConfigurator(common.Configurator):
"""
self._chall_out += len(achalls)
- responses: List[Optional[challenges.HTTP01Response]] = [None] * len(achalls)
+ responses: List[Optional[challenges.ChallengeResponse]] = [None] * len(achalls)
http_doer = http_01.NginxHttp01(self)
for i, achall in enumerate(achalls):
# Currently also have chall_doer hold associated index of the
# challenge. This helps to put all of the responses back together
# when they are all complete.
+ if not isinstance(achall, achallenges.KeyAuthorizationAnnotatedChallenge):
+ raise errors.Error("Challenge should be an instance "
+ "of KeyAuthorizationAnnotatedChallenge")
http_doer.add_chall(achall, i)
http_response = http_doer.perform()
diff --git a/certbot-nginx/certbot_nginx/_internal/http_01.py b/certbot-nginx/certbot_nginx/_internal/http_01.py
index 6f61bfb6f..f9988007e 100644
--- a/certbot-nginx/certbot_nginx/_internal/http_01.py
+++ b/certbot-nginx/certbot_nginx/_internal/http_01.py
@@ -11,7 +11,7 @@ from certbot_nginx._internal import nginxparser
from certbot_nginx._internal.obj import Addr
from acme import challenges
-from acme.challenges import HTTP01Response
+from acme.challenges import KeyAuthorizationChallengeResponse
from certbot import errors
from certbot.achallenges import KeyAuthorizationAnnotatedChallenge
from certbot.compat import os
@@ -49,10 +49,10 @@ class NginxHttp01(common.ChallengePerformer):
self.challenge_conf = os.path.join(
configurator.config.config_dir, "le_http_01_cert_challenge.conf")
- def perform(self) -> List[HTTP01Response]:
+ def perform(self) -> List[KeyAuthorizationChallengeResponse]:
"""Perform a challenge on Nginx.
- :returns: list of :class:`certbot.acme.challenges.HTTP01Response`
+ :returns: list of :class:`acme.challenges.KeyAuthorizationChallengeResponse`
:rtype: list
"""
diff --git a/certbot-nginx/certbot_nginx/_internal/nginxparser.py b/certbot-nginx/certbot_nginx/_internal/nginxparser.py
index 70a55be3a..0fdc71dfa 100644
--- a/certbot-nginx/certbot_nginx/_internal/nginxparser.py
+++ b/certbot-nginx/certbot_nginx/_internal/nginxparser.py
@@ -2,6 +2,7 @@
# Forked from https://github.com/fatiherikli/nginxparser (MIT Licensed)
import copy
import logging
+import operator
import typing
from typing import Any
from typing import IO
@@ -167,13 +168,14 @@ class UnspacedList(List[Any]):
inbound = UnspacedList(inbound)
return inbound, inbound.spaced
- def insert(self, i: int, x: Any) -> None:
+ def insert(self, i: "SupportsIndex", x: Any) -> None:
"""Insert object before index."""
+ idx = operator.index(i)
item, spaced_item = self._coerce(x)
- slicepos = self._spaced_position(i) if i < len(self) else len(self.spaced)
+ slicepos = self._spaced_position(idx) if idx < len(self) else len(self.spaced)
self.spaced.insert(slicepos, spaced_item)
if not spacey(item):
- super().insert(i, item)
+ super().insert(idx, item)
self.dirty = True
def append(self, x: Any) -> None:
@@ -246,7 +248,7 @@ class UnspacedList(List[Any]):
def _spaced_position(self, idx: "SupportsIndex") -> int:
"""Convert from indexes in the unspaced list to positions in the spaced one"""
- int_idx = idx.__index__()
+ int_idx = operator.index(idx)
pos = spaces = 0
# Normalize indexes like list[-1] etc, and save the result
if int_idx < 0:
diff --git a/certbot/certbot/_internal/account.py b/certbot/certbot/_internal/account.py
index 041fe9cf5..8c45efe21 100644
--- a/certbot/certbot/_internal/account.py
+++ b/certbot/certbot/_internal/account.py
@@ -54,9 +54,9 @@ class Account:
cross-machine migration scenarios.
"""
- creation_dt = acme_fields.RFC3339Field("creation_dt")
- creation_host = jose.Field("creation_host")
- register_to_eff = jose.Field("register_to_eff", omitempty=True)
+ creation_dt: datetime.datetime = acme_fields.rfc3339("creation_dt")
+ creation_host: str = jose.field("creation_host")
+ register_to_eff: str = jose.field("register_to_eff", omitempty=True)
def __init__(self, regr: messages.RegistrationResource, key: jose.JWK,
meta: Optional['Meta'] = None) -> None:
@@ -135,7 +135,7 @@ class RegistrationResourceWithNewAuthzrURI(messages.RegistrationResource):
continue to write out this field for some time so older
clients don't crash in that scenario.
"""
- new_authzr_uri = jose.Field('new_authzr_uri')
+ new_authzr_uri: str = jose.field('new_authzr_uri')
class AccountFileStorage(interfaces.AccountStorage):
diff --git a/certbot/certbot/_internal/auth_handler.py b/certbot/certbot/_internal/auth_handler.py
index 0fa1daf8e..08dc8be35 100644
--- a/certbot/certbot/_internal/auth_handler.py
+++ b/certbot/certbot/_internal/auth_handler.py
@@ -6,6 +6,7 @@ from typing import Dict
from typing import Iterable
from typing import List
from typing import Optional
+from typing import Sequence
from typing import Tuple
from typing import Type
@@ -272,7 +273,7 @@ class AuthHandler:
self.auth.cleanup(achalls)
def _challenge_factory(self, authzr: messages.AuthorizationResource,
- path: List[int]) -> List[achallenges.AnnotatedChallenge]:
+ path: Sequence[int]) -> List[achallenges.AnnotatedChallenge]:
"""Construct Namedtuple Challenges
:param messages.AuthorizationResource authzr: authorization
@@ -350,7 +351,7 @@ def challb_to_achall(challb: messages.ChallengeBody, account_key: josepy.JWK,
def gen_challenge_path(challbs: List[messages.ChallengeBody],
preferences: List[Type[challenges.Challenge]],
- combinations: Tuple[List[int], ...]) -> List[int]:
+ combinations: Tuple[Tuple[int, ...], ...]) -> Tuple[int, ...]:
"""Generate a plan to get authority over the identity.
.. todo:: This can be possibly be rewritten to use resolved_combinations.
@@ -383,8 +384,8 @@ def gen_challenge_path(challbs: List[messages.ChallengeBody],
def _find_smart_path(challbs: List[messages.ChallengeBody],
preferences: List[Type[challenges.Challenge]],
- combinations: Tuple[List[int], ...]
- ) -> List[int]:
+ combinations: Tuple[Tuple[int, ...], ...]
+ ) -> Tuple[int, ...]:
"""Find challenge path with server hints.
Can be called if combinations is included. Function uses a simple
@@ -399,7 +400,7 @@ def _find_smart_path(challbs: List[messages.ChallengeBody],
# max_cost is now equal to sum(indices) + 1
- best_combo: Optional[List[int]] = None
+ best_combo: Optional[Tuple[int, ...]] = None
# Set above completing all of the available challenges
best_combo_cost = max_cost
@@ -422,7 +423,7 @@ def _find_smart_path(challbs: List[messages.ChallengeBody],
def _find_dumb_path(challbs: List[messages.ChallengeBody],
- preferences: List[Type[challenges.Challenge]]) -> List[int]:
+ preferences: List[Type[challenges.Challenge]]) -> Tuple[int, ...]:
"""Find challenge path without server hints.
Should be called if the combinations hint is not included by the
@@ -440,7 +441,7 @@ def _find_dumb_path(challbs: List[messages.ChallengeBody],
else:
raise _report_no_chall_path(challbs)
- return path
+ return tuple(path)
def _report_no_chall_path(challbs: List[messages.ChallengeBody]) -> errors.AuthorizationError:
diff --git a/certbot/certbot/_internal/client.py b/certbot/certbot/_internal/client.py
index fec016ec7..ad5d99b61 100644
--- a/certbot/certbot/_internal/client.py
+++ b/certbot/certbot/_internal/client.py
@@ -251,7 +251,7 @@ def perform_registration(acme: acme_client.ClientV2, config: configuration.Names
raise errors.Error("The ACME client must be an instance of "
"acme.client.BackwardsCompatibleClientV2")
except messages.Error as e:
- if e.code in ('invalidEmail', 'invalidContact'):
+ if e.code in ("invalidEmail", "invalidContact"):
if config.noninteractive_mode:
msg = ("The ACME server believes %s is an invalid email address. "
"Please ensure it is a valid email and attempt "
diff --git a/certbot/certbot/_internal/plugins/manual.py b/certbot/certbot/_internal/plugins/manual.py
index dc45ae271..6c69b7e5b 100644
--- a/certbot/certbot/_internal/plugins/manual.py
+++ b/certbot/certbot/_internal/plugins/manual.py
@@ -98,7 +98,7 @@ permitted by DNS standards.)
super().__init__(*args, **kwargs)
self.reverter = reverter.Reverter(self.config)
self.reverter.recovery_routine()
- self.env: Dict[achallenges.KeyAuthorizationAnnotatedChallenge, Dict[str, str]] = {}
+ self.env: Dict[achallenges.AnnotatedChallenge, Dict[str, str]] = {}
self.subsequent_dns_challenge = False
self.subsequent_any_challenge = False
diff --git a/certbot/certbot/_internal/plugins/standalone.py b/certbot/certbot/_internal/plugins/standalone.py
index f70d2ed9e..826acb2b1 100644
--- a/certbot/certbot/_internal/plugins/standalone.py
+++ b/certbot/certbot/_internal/plugins/standalone.py
@@ -30,7 +30,7 @@ logger = logging.getLogger(__name__)
if TYPE_CHECKING:
ServedType = DefaultDict[
acme_standalone.BaseDualNetworkedServers,
- Set[achallenges.KeyAuthorizationAnnotatedChallenge]
+ Set[achallenges.AnnotatedChallenge]
]
diff --git a/certbot/certbot/_internal/plugins/webroot.py b/certbot/certbot/_internal/plugins/webroot.py
index bb61d8220..4a84197b0 100644
--- a/certbot/certbot/_internal/plugins/webroot.py
+++ b/certbot/certbot/_internal/plugins/webroot.py
@@ -20,7 +20,7 @@ from certbot import crypto_util
from certbot import errors
from certbot import interfaces
from certbot._internal import cli
-from certbot.achallenges import KeyAuthorizationAnnotatedChallenge as AnnotatedChallenge
+from certbot.achallenges import AnnotatedChallenge
from certbot.compat import filesystem
from certbot.compat import os
from certbot.display import ops
@@ -85,7 +85,7 @@ to serve all files under specified web root ({0})."""
"file, it needs to be on a single line, like: webroot-map = "
'{"example.com":"/var/www"}.')
- def auth_hint(self, failed_achalls: Iterable[AnnotatedChallenge]) -> str: # pragma: no cover
+ def auth_hint(self, failed_achalls: List[AnnotatedChallenge]) -> str: # pragma: no cover
return ("The Certificate Authority failed to download the temporary challenge files "
"created by Certbot. Ensure that the listed domains serve their content from "
"the provided --webroot-path/-w and that files created there can be downloaded "
@@ -105,7 +105,7 @@ to serve all files under specified web root ({0})."""
def prepare(self) -> None: # pylint: disable=missing-function-docstring
pass
- def perform(self, achalls: Iterable[AnnotatedChallenge]) -> List[challenges.ChallengeResponse]: # pylint: disable=missing-function-docstring
+ def perform(self, achalls: List[AnnotatedChallenge]) -> List[challenges.ChallengeResponse]: # pylint: disable=missing-function-docstring
self._set_webroots(achalls)
self._create_challenge_dirs()
@@ -257,7 +257,7 @@ to serve all files under specified web root ({0})."""
self.performed[root_path].add(achall)
return response
- def cleanup(self, achalls: Iterable[AnnotatedChallenge]) -> None: # pylint: disable=missing-function-docstring
+ def cleanup(self, achalls: List[AnnotatedChallenge]) -> None: # pylint: disable=missing-function-docstring
for achall in achalls:
root_path = self.full_roots.get(achall.domain, None)
if root_path is not None:
diff --git a/certbot/certbot/_internal/reporter.py b/certbot/certbot/_internal/reporter.py
index 333fcca48..fb09b1f27 100644
--- a/certbot/certbot/_internal/reporter.py
+++ b/certbot/certbot/_internal/reporter.py
@@ -29,7 +29,7 @@ class Reporter:
_msg_type = collections.namedtuple('_msg_type', 'priority text on_crash')
def __init__(self, config: configuration.NamespaceConfig) -> None:
- self.messages: queue.PriorityQueue[Reporter._msg_type] = queue.PriorityQueue()
+ self.messages: "queue.PriorityQueue[Reporter._msg_type]" = queue.PriorityQueue()
self.config = config
def add_message(self, msg: str, priority: int, on_crash: bool = True) -> None:
diff --git a/certbot/certbot/_internal/snap_config.py b/certbot/certbot/_internal/snap_config.py
index 3aad79912..f006c8be1 100644
--- a/certbot/certbot/_internal/snap_config.py
+++ b/certbot/certbot/_internal/snap_config.py
@@ -18,8 +18,8 @@ try:
from urllib3.connectionpool import HTTPConnectionPool
except ImportError:
# Stub imports for oldest requirements, that will never be used in snaps.
- HTTPConnection = object
- HTTPConnectionPool = object
+ HTTPConnection = object # type: ignore[misc,assignment]
+ HTTPConnectionPool = object # type: ignore[misc,assignment]
_ARCH_TRIPLET_MAP = {
diff --git a/certbot/certbot/crypto_util.py b/certbot/certbot/crypto_util.py
index e3a62cc9e..ef86c5e46 100644
--- a/certbot/certbot/crypto_util.py
+++ b/certbot/certbot/crypto_util.py
@@ -290,8 +290,11 @@ def make_key(bits: int = 1024, key_type: str = "rsa",
try:
name = elliptic_curve.upper()
if name in ('SECP256R1', 'SECP384R1', 'SECP521R1'):
+ curve = getattr(ec, elliptic_curve.upper())
+ if not curve:
+ raise errors.Error(f"Invalid curve type: {elliptic_curve}")
_key = ec.generate_private_key(
- curve=getattr(ec, elliptic_curve.upper(), None)(),
+ curve=curve(),
backend=default_backend()
)
else:
diff --git a/certbot/certbot/plugins/common.py b/certbot/certbot/plugins/common.py
index 3af0ee6ec..fbecc7372 100644
--- a/certbot/certbot/plugins/common.py
+++ b/certbot/certbot/plugins/common.py
@@ -18,6 +18,8 @@ from typing import Tuple
import pkg_resources
+from acme import challenges
+
from certbot import achallenges
from certbot import configuration
from certbot import crypto_util
@@ -377,7 +379,7 @@ class ChallengePerformer:
if idx is not None:
self.indices.append(idx)
- def perform(self) -> List[achallenges.KeyAuthorizationAnnotatedChallenge]:
+ def perform(self) -> List[challenges.KeyAuthorizationChallengeResponse]:
"""Perform all added challenges.
:returns: challenge responses
diff --git a/certbot/certbot/plugins/dns_test_common_lexicon.py b/certbot/certbot/plugins/dns_test_common_lexicon.py
index df91dac1f..7d844d133 100644
--- a/certbot/certbot/plugins/dns_test_common_lexicon.py
+++ b/certbot/certbot/plugins/dns_test_common_lexicon.py
@@ -7,8 +7,8 @@ import josepy as jose
from requests.exceptions import HTTPError
from requests.exceptions import RequestException
-from acme.challenges import Challenge
from certbot import errors
+from certbot.achallenges import AnnotatedChallenge
from certbot.plugins import dns_test_common
from certbot.plugins.dns_common_lexicon import LexiconClient
from certbot.plugins.dns_test_common import _AuthenticatorCallableTestCase
@@ -33,7 +33,7 @@ class _AuthenticatorCallableLexiconTestCase(_AuthenticatorCallableTestCase, Prot
a mocked LexiconClient instance.
"""
mock_client: MagicMock
- achall: Challenge
+ achall: AnnotatedChallenge
class _LexiconAwareTestCase(Protocol):
diff --git a/certbot/certbot/tests/acme_util.py b/certbot/certbot/tests/acme_util.py
index 0c164ecb4..d8ee7f9a8 100644
--- a/certbot/certbot/tests/acme_util.py
+++ b/certbot/certbot/tests/acme_util.py
@@ -1,5 +1,7 @@
"""ACME utilities for testing."""
import datetime
+from typing import Any
+from typing import Dict
from typing import Iterable
from typing import Tuple
@@ -74,7 +76,7 @@ def gen_authzr(authz_status: messages.Status, domain: str, challs: Iterable[chal
chall_to_challb(chall, status)
for chall, status in zip(challs, statuses)
)
- authz_kwargs = {
+ authz_kwargs: Dict[str, Any] = {
"identifier": messages.Identifier(
typ=messages.IDENTIFIER_FQDN, value=domain),
"challenges": challbs,
diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt
index 819cbfda6..a3ffc16ab 100644
--- a/tools/oldest_constraints.txt
+++ b/tools/oldest_constraints.txt
@@ -2,10 +2,9 @@
# that script.
apacheconfig==0.3.2
asn1crypto==0.24.0
-astroid==2.8.6; python_version >= "3.6" and python_version < "4.0"
+astroid==2.9.0; python_version >= "3.6" and python_version < "4.0"
atomicwrites==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.4.0"
-attrs==21.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
-backports.entry-points-selectable==1.1.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
+attrs==21.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
bcrypt==3.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
boto3==1.4.7
botocore==1.7.41
@@ -16,10 +15,10 @@ cloudflare==1.5.1
colorama==0.4.4; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or python_full_version >= "3.5.0" and python_version >= "3.6" and sys_platform == "win32" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.6" and python_version < "4.0" and sys_platform == "win32" and python_full_version >= "3.5.0"
configargparse==0.10.0
configobj==5.0.6
-coverage==6.1.2; python_version >= "3.6" or python_version >= "3.6"
+coverage==6.2; python_version >= "3.6" or python_version >= "3.6"
cryptography==3.2.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0")
-cython==0.29.24; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0")
-distlib==0.3.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
+cython==0.29.26; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0")
+distlib==0.3.4; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
distro==1.0.1
dns-lexicon==3.2.1
dnspython==1.15.0
@@ -30,30 +29,30 @@ dockerpty==0.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or p
docopt==0.6.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
docutils==0.18.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
execnet==1.9.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
-filelock==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6"
+filelock==3.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6"
funcsigs==0.4
future==0.18.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
google-api-python-client==1.5.5
httplib2==0.9.2
idna==2.6
-importlib-metadata==4.8.2; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_full_version >= "3.5.0" and python_version < "3.8" or python_version < "3.8" and python_version >= "3.6"
+importlib-metadata==4.8.3; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_full_version >= "3.5.0" and python_version < "3.8" or python_version < "3.8" and python_version >= "3.6"
importlib-resources==5.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_full_version >= "3.5.0" and python_version < "3.7"
iniconfig==1.1.1; python_version >= "3.6"
ipaddress==1.0.16
isort==5.8.0; python_version >= "3.6" and python_version < "4.0"
jmespath==0.10.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
-josepy==1.11.0; python_version >= "3.6"
+josepy==1.12.0; python_version >= "3.6"
jsonschema==2.6.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
-lazy-object-proxy==1.6.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.6.0"
+lazy-object-proxy==1.7.1; python_version >= "3.6" and python_version < "4.0"
logger==1.4; python_version >= "3.6"
mccabe==0.6.1; python_version >= "3.6" and python_version < "4.0"
mock==1.0.1
mypy-extensions==0.4.3; python_version >= "3.6"
-mypy==0.910; python_version >= "3.6"
+mypy==0.931; python_version >= "3.6"
ndg-httpsclient==0.3.2
oauth2client==4.0.0
packaging==21.3; python_version >= "3.6"
-paramiko==2.8.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
+paramiko==2.9.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
parsedatetime==2.4
pbr==1.8.0
pip==21.3.1; python_version >= "3.6"
@@ -64,21 +63,21 @@ py==1.11.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_
pyasn1-modules==0.0.10; python_version >= "3.6"
pyasn1==0.1.9
pycparser==2.14
-pylint==2.11.1; python_version >= "3.6" and python_version < "4.0"
-pynacl==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
+pylint==2.12.0; python_version >= "3.6" and python_version < "4.0"
+pynacl==1.5.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
pyopenssl==17.3.0
pyparsing==2.2.0
pypiwin32==223; sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6")
pyrfc3339==1.0
pytest-cov==3.0.0; python_version >= "3.6" or python_version >= "3.6"
-pytest-forked==1.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
-pytest-xdist==2.4.0; python_version >= "3.6" or python_version >= "3.6"
-pytest==6.2.5; python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
+pytest-forked==1.4.0; python_version >= "3.6"
+pytest-xdist==2.5.0; python_version >= "3.6" or python_version >= "3.6"
+pytest==6.2.5; python_version >= "3.6" or python_version >= "3.6"
python-augeas==0.5.0
python-dateutil==2.8.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
python-digitalocean==1.11
pytz==2012c
-pywin32==302; sys_platform == "win32" and python_version >= "3.6" or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6")
+pywin32==303; sys_platform == "win32" and python_version >= "3.6" or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6")
pyyaml==3.13; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6"
requests-file==1.5.1; python_version >= "3.6"
requests-toolbelt==0.9.1; python_version >= "3.6"
@@ -90,24 +89,25 @@ six==1.11.0
texttable==0.9.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
tldextract==3.1.2; python_version >= "3.6"
toml==0.10.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.3.0"
-tomli==1.2.2; python_version >= "3.6"
+tomli==1.2.3; python_version >= "3.6"
tox==1.9.2; python_version >= "3.6"
-typed-ast==1.4.3; python_version >= "3.6" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.6"
-types-cryptography==3.3.9; python_version >= "3.6"
-types-enum34==1.1.1; python_version >= "3.6"
-types-ipaddress==1.0.1; python_version >= "3.6"
-types-mock==4.0.3; python_version >= "3.6"
-types-pyopenssl==21.0.1; python_version >= "3.6"
-types-pyrfc3339==1.1.0; python_version >= "3.6"
-types-python-dateutil==2.8.3; python_version >= "3.6"
-types-pytz==2021.3.1; python_version >= "3.6"
-types-requests==2.26.0; python_version >= "3.6"
-types-setuptools==57.4.3; python_version >= "3.6"
-types-six==1.16.2; python_version >= "3.6"
-typing-extensions==4.0.0; python_version >= "3.6" or python_version >= "3.6" and python_version < "3.10" or python_version < "3.8" and python_version >= "3.6"
+typed-ast==1.5.1; python_version >= "3.6" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.6"
+types-cryptography==3.3.14; python_version >= "3.6"
+types-enum34==1.1.7; python_version >= "3.6"
+types-ipaddress==1.0.7; python_version >= "3.6"
+types-mock==4.0.8; python_version >= "3.6"
+types-pyopenssl==21.0.3; python_version >= "3.6"
+types-pyrfc3339==1.1.1; python_version >= "3.6"
+types-python-dateutil==2.8.7; python_version >= "3.6"
+types-pytz==2021.3.4; python_version >= "3.6"
+types-requests==2.27.7; python_version >= "3.6"
+types-setuptools==57.4.7; python_version >= "3.6"
+types-six==1.16.10; python_version >= "3.6"
+types-urllib3==1.26.7; python_version >= "3.6"
+typing-extensions==4.0.1; python_version >= "3.6" or python_version >= "3.6" and python_version < "3.10" or python_version < "3.8" and python_version >= "3.6"
uritemplate==3.0.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
urllib3==1.10.2
-virtualenv==20.10.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
+virtualenv==20.13.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
websocket-client==0.59.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
wheel==0.33.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0")
wrapt==1.13.3; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0"
diff --git a/tools/pinning/current/pyproject.toml b/tools/pinning/current/pyproject.toml
index c04180b06..ca04a0ada 100644
--- a/tools/pinning/current/pyproject.toml
+++ b/tools/pinning/current/pyproject.toml
@@ -51,10 +51,6 @@ awscli = ">=1.19.62"
# as a dependency here to ensure a version of cython is pinned for extra
# stability.
cython = "*"
-# Due to better type annotations in new versions, mypy tests currently fail
-# with new versions of josepy so we pin it back for now. Fixing this is being
-# tracked by https://github.com/certbot/certbot/issues/9113.
-josepy = "1.9.0"
# We install mock in our "external-mock" tox environment to test that we didn't
# break Certbot's test API which used to always use mock objects from the 3rd
# party mock library. We list the mock dependency here so that is pinned, but
diff --git a/tools/requirements.txt b/tools/requirements.txt
index 38bf7c0cc..c91bf2117 100644
--- a/tools/requirements.txt
+++ b/tools/requirements.txt
@@ -9,41 +9,41 @@ alabaster==0.7.12; python_version >= "3.6"
apacheconfig==0.3.2; python_version >= "3.6"
appdirs==1.4.4; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0"
appnope==0.1.2; python_version == "3.6" and sys_platform == "darwin" or python_version >= "3.7" and sys_platform == "darwin"
-astroid==2.8.6; python_version >= "3.6" and python_version < "4.0"
+astroid==2.9.0; python_version >= "3.6" and python_version < "4.0"
atomicwrites==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.4.0"
-attrs==21.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
-awscli==1.22.11; python_version >= "3.6"
+attrs==21.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
+awscli==1.22.39; python_version >= "3.6"
azure-devops==6.0.0b4; python_version >= "3.6"
babel==2.9.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
backcall==0.2.0; python_version == "3.6" or python_version >= "3.7"
bcrypt==3.2.0; python_version >= "3.6"
beautifulsoup4==4.10.0; python_full_version > "3.0.0" and python_version >= "3.6" or python_version >= "3.6" and python_version < "4.0" and python_full_version > "3.0.0"
bleach==4.1.0; python_version >= "3.6"
-boto3==1.20.11; python_version >= "3.6"
-botocore==1.23.11; python_version >= "3.6"
+boto3==1.20.39; python_version >= "3.6"
+botocore==1.23.39; python_version >= "3.6"
cachecontrol==0.12.10; python_version >= "3.6" and python_version < "4.0"
cached-property==1.5.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
cachetools==4.2.4; python_version >= "3.5" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6")
cachy==0.3.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0"
certifi==2021.10.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6"
-cffi==1.15.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" or python_version >= "3.6"
-charset-normalizer==2.0.7; python_full_version >= "3.6.0" and python_version >= "3.6"
+cffi==1.15.0; python_version >= "3.6" or python_version >= "3.6"
+charset-normalizer==2.0.10; python_full_version >= "3.6.0" and python_version >= "3.6"
cleo==1.0.0a4; python_version >= "3.6" and python_version < "4.0"
cloudflare==2.8.15; python_version >= "3.6"
colorama==0.4.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or python_full_version >= "3.5.0" and python_version >= "3.6" and sys_platform == "win32" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.6" and python_version < "4.0" and sys_platform == "win32" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and platform_system == "Windows" or python_version >= "3.6" and python_full_version >= "3.5.0" and platform_system == "Windows" or python_version == "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or python_version == "3.6" and sys_platform == "win32" and python_full_version >= "3.5.0" or python_version >= "3.7" and python_full_version < "3.0.0" and sys_platform == "win32" or python_version >= "3.7" and sys_platform == "win32" and python_full_version >= "3.5.0"
configargparse==1.5.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
configobj==5.0.6; python_version >= "3.6"
-coverage==6.1.2; python_version >= "3.6" or python_version >= "3.6"
+coverage==6.2; python_version >= "3.6" or python_version >= "3.6"
crashtest==0.3.1; python_version >= "3.6" and python_version < "4.0"
-cryptography==36.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and sys_platform == "linux"
-cython==0.29.24; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0")
+cryptography==36.0.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and sys_platform == "linux"
+cython==0.29.26; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0")
dataclasses==0.8; python_version >= "3.6" and python_version < "3.7"
-decorator==5.1.0; python_version == "3.6" or python_version > "3.6" or python_version >= "3.5" or python_version >= "3.7"
+decorator==5.1.1; python_version == "3.6" or python_version > "3.6" or python_version >= "3.5" or python_version >= "3.7"
deprecated==1.2.13; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
-distlib==0.3.3; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6"
+distlib==0.3.4; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6"
distro==1.6.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6"
-dns-lexicon==3.8.3; python_version >= "3.6" and python_version < "4.0"
-dnspython==2.1.0; python_version >= "3.6"
+dns-lexicon==3.8.5; python_version >= "3.6" and python_version < "4.0"
+dnspython==2.2.0; python_version >= "3.6" and python_version < "4.0"
docker-compose==1.26.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
docker==4.2.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
dockerpty==0.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
@@ -52,12 +52,12 @@ docutils==0.15.2; python_version >= "3.6" and python_full_version < "3.0.0" or p
entrypoints==0.3; python_version >= "3.6" and python_version < "4.0"
execnet==1.9.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
fabric==2.6.0; python_version >= "3.6"
-filelock==3.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_version < "4.0"
-google-api-core==2.2.2; python_version >= "3.6"
-google-api-python-client==2.31.0; python_version >= "3.6"
+filelock==3.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_version < "4.0"
+google-api-core==2.4.0; python_version >= "3.6"
+google-api-python-client==2.36.0; python_version >= "3.6"
google-auth-httplib2==0.1.0; python_version >= "3.6"
google-auth==2.3.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
-googleapis-common-protos==1.53.0; python_version >= "3.6"
+googleapis-common-protos==1.54.0; python_version >= "3.6"
html5lib==1.1; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0"
httplib2==0.20.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
idna==3.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_version < "4.0"
@@ -68,58 +68,60 @@ iniconfig==1.1.1; python_version >= "3.6"
invoke==1.6.0; python_version >= "3.6"
ipdb==0.13.9; python_version >= "3.6"
ipython-genutils==0.2.0
-ipython==7.16.1; python_version == "3.6"
-ipython==7.29.0; python_version >= "3.7"
-isodate==0.6.0; python_version >= "3.6"
+ipython==7.16.3; python_version == "3.6"
+ipython==7.31.1; python_version >= "3.7"
+isodate==0.6.1; python_version >= "3.6"
isort==5.8.0; python_version >= "3.6" and python_version < "4.0"
-jedi==0.18.1; python_version == "3.6" or python_version >= "3.7"
+jedi==0.17.2; python_version == "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.5.0"
+jedi==0.18.1; python_version >= "3.7"
jeepney==0.7.1; python_version >= "3.6" and python_version < "4.0" and sys_platform == "linux"
jinja2==3.0.3; python_version >= "3.6" or python_version >= "3.6"
jmespath==0.10.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
-josepy==1.9.0; python_version >= "3.6"
-jsonlines==2.0.0; python_version >= "3.6"
-jsonpickle==2.0.0; python_version >= "3.6"
+josepy==1.12.0; python_version >= "3.6"
+jsonlines==3.0.0; python_version >= "3.6"
+jsonpickle==2.1.0; python_version >= "3.6"
jsonschema==3.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
keyring==22.3.0; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6"
-lazy-object-proxy==1.6.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.6.0"
+lazy-object-proxy==1.7.1; python_version >= "3.6" and python_version < "4.0"
lockfile==0.12.2
markupsafe==2.0.1; python_version >= "3.6"
matplotlib-inline==0.1.3; python_version >= "3.7"
mccabe==0.6.1; python_version >= "3.6" and python_version < "4.0"
mock==4.0.3; python_version >= "3.6"
-msgpack==1.0.2; python_version >= "3.6" and python_version < "4.0"
+msgpack==1.0.3; python_version >= "3.6" and python_version < "4.0"
msrest==0.6.21; python_version >= "3.6"
mypy-extensions==0.4.3; python_version >= "3.6"
-mypy==0.910; python_version >= "3.6"
+mypy==0.931; python_version >= "3.6"
oauth2client==4.1.3; python_version >= "3.6"
oauthlib==3.1.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
packaging==20.9; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version >= "3.5.0"
-paramiko==2.8.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_version >= "3.6"
+paramiko==2.9.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_version >= "3.6"
parsedatetime==2.6; python_version >= "3.6"
-parso==0.8.2; python_version == "3.6"
+parso==0.7.1; python_version == "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.5.0"
+parso==0.8.3; python_version >= "3.7"
pathlib2==2.3.6; python_version >= "3.6"
pexpect==4.8.0; python_version >= "3.6" and python_version < "4.0" or python_version == "3.6" and sys_platform != "win32" or python_version >= "3.7" and sys_platform != "win32"
pickleshare==0.7.5; python_version == "3.6" or python_version >= "3.7"
pip==21.3.1; python_version >= "3.6"
-pkginfo==1.8.1; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6"
+pkginfo==1.8.2; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6"
platformdirs==2.4.0; python_version >= "3.6" and python_version < "4.0"
pluggy==1.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6"
ply==3.11; python_version >= "3.6"
poetry-core==1.1.0a6; python_version >= "3.6" and python_version < "4.0"
poetry==1.2.0a2; python_version >= "3.6" and python_version < "4.0"
-prompt-toolkit==3.0.22; python_version == "3.6" and python_full_version >= "3.6.2" or python_version >= "3.7" and python_full_version >= "3.6.2"
-protobuf==3.19.1; python_version >= "3.6"
+prompt-toolkit==3.0.24; python_version == "3.6" and python_full_version >= "3.6.2" or python_version >= "3.7" and python_full_version >= "3.6.2"
+protobuf==3.19.3; python_version >= "3.6"
ptyprocess==0.7.0; python_version >= "3.6" and python_version < "4.0"
py==1.11.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
pyasn1-modules==0.2.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6"
pyasn1==0.4.8; python_version >= "3.6" and python_version < "4" or python_version >= "3.6"
pycparser==2.21; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
pygithub==1.55; python_version >= "3.6"
-pygments==2.10.0; python_version >= "3.6" or python_version == "3.6" or python_version >= "3.7"
+pygments==2.11.2; python_version >= "3.6" or python_version == "3.6" or python_version >= "3.7"
pyjwt==2.3.0; python_version >= "3.6"
pylev==1.4.0; python_version >= "3.6" and python_version < "4.0"
-pylint==2.11.1; python_version >= "3.6" and python_version < "4.0"
-pynacl==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
+pylint==2.12.0; python_version >= "3.6" and python_version < "4.0"
+pynacl==1.5.0; python_version >= "3.6" or python_version >= "3.6"
pynsist==2.7; python_version >= "3.6"
pyopenssl==21.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
pyparsing==3.0.6; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0"
@@ -127,36 +129,36 @@ pypiwin32==223; sys_platform == "win32" and python_version >= "3.6" and (python_
pyrfc3339==1.1; python_version >= "3.6"
pyrsistent==0.18.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
pytest-cov==3.0.0; python_version >= "3.6" or python_version >= "3.6"
-pytest-forked==1.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
-pytest-xdist==2.4.0; python_version >= "3.6" or python_version >= "3.6"
-pytest==6.2.5; python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
+pytest-forked==1.4.0; python_version >= "3.6"
+pytest-xdist==2.5.0; python_version >= "3.6" or python_version >= "3.6"
+pytest==6.2.5; python_version >= "3.6" or python_version >= "3.6"
python-augeas==1.1.0; python_version >= "3.6"
python-dateutil==2.8.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
python-digitalocean==1.17.0; python_version >= "3.6"
python-dotenv==0.19.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
pytz==2021.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" or python_version >= "3.6"
pywin32-ctypes==0.2.0; python_version >= "3.6" and python_version < "4.0" and sys_platform == "win32"
-pywin32==302; sys_platform == "win32" and python_version >= "3.6" or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6")
+pywin32==303; sys_platform == "win32" and python_version >= "3.6" or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6")
pyyaml==5.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.6.0"
-readme-renderer==30.0; python_version >= "3.6"
+readme-renderer==32.0; python_version >= "3.6"
requests-download==0.1.2; python_version >= "3.6"
requests-file==1.5.1; python_version >= "3.6" and python_version < "4.0"
requests-oauthlib==1.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
requests-toolbelt==0.9.1; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6" or python_version >= "3.6"
-requests==2.26.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.6.0"
+requests==2.27.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.6.0"
rfc3986==1.5.0; python_version >= "3.6"
rsa==4.7.2; python_version >= "3.6" and python_version < "4" or python_version >= "3.5" and python_version < "4" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6")
s3transfer==0.5.0; python_version >= "3.6"
secretstorage==3.3.1; python_version >= "3.6" and python_version < "4.0" and sys_platform == "linux"
semantic-version==2.8.5; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
setuptools-rust==0.12.1; python_version >= "3.6"
-setuptools==59.2.0; python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version == "3.6" or python_version >= "3.7" or python_version >= "3.6" and python_version < "4.0"
+setuptools==59.6.0; python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version == "3.6" or python_version >= "3.7" or python_version >= "3.6" and python_version < "4.0"
shellingham==1.4.0; python_version >= "3.6" and python_version < "4.0"
six==1.16.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_full_version >= "3.3.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.3.0" or python_version == "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.3.0"
snowballstemmer==2.2.0; python_version >= "3.6"
soupsieve==2.3.1; python_full_version > "3.0.0" and python_version >= "3.6"
sphinx-rtd-theme==1.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
-sphinx==4.3.0; python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
+sphinx==4.3.2; python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
sphinxcontrib-applehelp==1.0.2; python_version >= "3.6"
sphinxcontrib-devhelp==1.0.2; python_version >= "3.6"
sphinxcontrib-htmlhelp==2.0.0; python_version >= "3.6"
@@ -166,32 +168,33 @@ sphinxcontrib-serializinghtml==1.1.5; python_version >= "3.6"
texttable==1.6.4; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
tldextract==3.1.2; python_version >= "3.6" and python_version < "4.0"
toml==0.10.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" or python_version == "3.6" and python_full_version < "3.0.0" or python_version > "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.3.0" or python_version > "3.6" and python_full_version >= "3.3.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.3.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
-tomli==1.2.2; python_version >= "3.6"
-tomlkit==0.7.2; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0"
-tox==3.24.4; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
+tomli==1.2.3; python_version >= "3.6"
+tomlkit==0.8.0; python_version >= "3.6" and python_version < "4.0"
+tox==3.24.5; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
tqdm==4.62.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
traitlets==4.3.3
twine==3.3.0; python_version >= "3.6"
-typed-ast==1.4.3; python_version >= "3.6" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.6"
-types-cryptography==3.3.8; python_version >= "3.6"
-types-enum34==1.1.1; python_version >= "3.6"
-types-ipaddress==1.0.1; python_version >= "3.6"
-types-mock==4.0.3; python_version >= "3.6"
-types-pyopenssl==21.0.0; python_version >= "3.6"
-types-pyrfc3339==1.1.0; python_version >= "3.6"
-types-python-dateutil==2.8.2; python_version >= "3.6"
-types-pytz==2021.3.0; python_version >= "3.6"
-types-requests==2.26.0; python_version >= "3.6"
-types-setuptools==57.4.2; python_version >= "3.6"
-types-six==1.16.2; python_version >= "3.6"
-typing-extensions==4.0.0; python_version >= "3.6" or python_version >= "3.6" and python_version < "3.10"
+typed-ast==1.5.1; python_version >= "3.6" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.6"
+types-cryptography==3.3.14; python_version >= "3.6"
+types-enum34==1.1.7; python_version >= "3.6"
+types-ipaddress==1.0.7; python_version >= "3.6"
+types-mock==4.0.8; python_version >= "3.6"
+types-pyopenssl==21.0.3; python_version >= "3.6"
+types-pyrfc3339==1.1.1; python_version >= "3.6"
+types-python-dateutil==2.8.7; python_version >= "3.6"
+types-pytz==2021.3.4; python_version >= "3.6"
+types-requests==2.27.7; python_version >= "3.6"
+types-setuptools==57.4.7; python_version >= "3.6"
+types-six==1.16.10; python_version >= "3.6"
+types-urllib3==1.26.7; python_version >= "3.6"
+typing-extensions==4.0.1; python_version >= "3.6" or python_version >= "3.6" and python_version < "3.10" or python_version < "3.8" and python_version >= "3.6"
uritemplate==4.1.1; python_version >= "3.6"
-urllib3==1.26.7; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.6" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.6"
+urllib3==1.26.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.6" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.6"
virtualenv==20.4.4; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
wcwidth==0.2.5; python_version == "3.6" and python_full_version >= "3.6.2"
webencodings==0.5.1; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0" or python_version >= "3.6"
websocket-client==0.59.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_full_version >= "3.5.0" and python_version >= "3.6"
-wheel==0.37.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
+wheel==0.37.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
wrapt==1.13.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0"
yarg==0.1.9; python_version >= "3.6"
zipp==3.6.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_version < "3.8" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.4.0"