Compare commits
15 Commits
test-drop-
...
test-reena
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0360ac47d6 | ||
|
|
2ced0de4fe | ||
|
|
693abd4a27 | ||
|
|
ef6d46d808 | ||
|
|
ec2441f773 | ||
|
|
b5104e9168 | ||
|
|
75299aa1ff | ||
|
|
4aeda88633 | ||
|
|
09ec53ccf2 | ||
|
|
429bbfbf39 | ||
|
|
f10d4cca62 | ||
|
|
602a74e452 | ||
|
|
6fa3472db5 | ||
|
|
1e3f56ef1b | ||
|
|
96cf1e7ea9 |
@@ -5,4 +5,3 @@ pr:
|
||||
|
||||
jobs:
|
||||
- template: templates/jobs/standard-tests-jobs.yml
|
||||
|
||||
|
||||
@@ -22,21 +22,25 @@ jobs:
|
||||
TOXENV: py37
|
||||
CERTBOT_NO_PIN: 1
|
||||
linux-boulder-v1-integration-certbot-oldest:
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: integration-certbot-oldest
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-integration-certbot-oldest:
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: integration-certbot-oldest
|
||||
ACME_SERVER: boulder-v2
|
||||
linux-boulder-v1-integration-nginx-oldest:
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: integration-nginx-oldest
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-integration-nginx-oldest:
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: integration-nginx-oldest
|
||||
ACME_SERVER: boulder-v2
|
||||
linux-boulder-v1-py27-integration:
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-py27-integration:
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v2
|
||||
linux-boulder-v1-py36-integration:
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: integration
|
||||
|
||||
@@ -50,168 +50,3 @@ jobs:
|
||||
do docker run --rm "${DOCKER_IMAGE}" plugins --prepare
|
||||
done
|
||||
displayName: Run integration tests for Docker images
|
||||
- job: installer_build
|
||||
pool:
|
||||
vmImage: vs2017-win2016
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: 3.8
|
||||
architecture: x86
|
||||
addToPath: true
|
||||
- script: python windows-installer/construct.py
|
||||
displayName: Build Certbot installer
|
||||
- task: CopyFiles@2
|
||||
inputs:
|
||||
sourceFolder: $(System.DefaultWorkingDirectory)/windows-installer/build/nsis
|
||||
contents: '*.exe'
|
||||
targetFolder: $(Build.ArtifactStagingDirectory)
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
# If we change the artifact's name, it should also be changed in tools/create_github_release.py
|
||||
artifact: windows-installer
|
||||
displayName: Publish Windows installer
|
||||
- job: installer_run
|
||||
dependsOn: installer_build
|
||||
strategy:
|
||||
matrix:
|
||||
win2019:
|
||||
imageName: windows-2019
|
||||
win2016:
|
||||
imageName: vs2017-win2016
|
||||
pool:
|
||||
vmImage: $(imageName)
|
||||
steps:
|
||||
- powershell: |
|
||||
if ($PSVersionTable.PSVersion.Major -ne 5) {
|
||||
throw "Powershell version is not 5.x"
|
||||
}
|
||||
condition: eq(variables['imageName'], 'vs2017-win2016')
|
||||
displayName: Check Powershell 5.x is used in vs2017-win2016
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: 3.8
|
||||
addToPath: true
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: windows-installer
|
||||
path: $(Build.SourcesDirectory)/bin
|
||||
displayName: Retrieve Windows installer
|
||||
- script: |
|
||||
python -m venv venv
|
||||
venv\Scripts\python tools\pipstrap.py
|
||||
venv\Scripts\python tools\pip_install.py -e certbot-ci
|
||||
env:
|
||||
PIP_NO_BUILD_ISOLATION: no
|
||||
displayName: Prepare Certbot-CI
|
||||
- script: |
|
||||
set PATH=%ProgramFiles(x86)%\Certbot\bin;%PATH%
|
||||
venv\Scripts\python -m pytest certbot-ci\windows_installer_integration_tests --allow-persistent-changes --installer-path $(Build.SourcesDirectory)\bin\certbot-beta-installer-win32.exe
|
||||
displayName: Run windows installer integration tests
|
||||
- script: |
|
||||
set PATH=%ProgramFiles(x86)%\Certbot\bin;%PATH%
|
||||
venv\Scripts\python -m pytest certbot-ci\certbot_integration_tests\certbot_tests -n 4
|
||||
displayName: Run certbot integration tests
|
||||
- job: snaps_build
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
timeoutInMinutes: 0
|
||||
variables:
|
||||
# Do not run the heavy non-amd64 builds for test branches
|
||||
${{ if not(startsWith(variables['Build.SourceBranchName'], 'test-')) }}:
|
||||
ARCHS: amd64 arm64 armhf
|
||||
${{ if startsWith(variables['Build.SourceBranchName'], 'test-') }}:
|
||||
ARCHS: amd64
|
||||
steps:
|
||||
- script: |
|
||||
set -e
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends snapd
|
||||
sudo snap install --classic snapcraft
|
||||
displayName: Install dependencies
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: 3.8
|
||||
addToPath: true
|
||||
- task: DownloadSecureFile@1
|
||||
name: credentials
|
||||
inputs:
|
||||
secureFile: launchpad-credentials
|
||||
- script: |
|
||||
set -e
|
||||
git config --global user.email "$(Build.RequestedForEmail)"
|
||||
git config --global user.name "$(Build.RequestedFor)"
|
||||
mkdir -p ~/.local/share/snapcraft/provider/launchpad
|
||||
cp $(credentials.secureFilePath) ~/.local/share/snapcraft/provider/launchpad/credentials
|
||||
python3 tools/snap/build_remote.py ALL --archs ${ARCHS} --timeout 19800
|
||||
displayName: Build snaps
|
||||
- script: |
|
||||
set -e
|
||||
mv *.snap $(Build.ArtifactStagingDirectory)
|
||||
mv certbot-dns-*/*.snap $(Build.ArtifactStagingDirectory)
|
||||
displayName: Prepare artifacts
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
artifact: snaps
|
||||
displayName: Store snaps artifacts
|
||||
- job: snap_run
|
||||
dependsOn: snaps_build
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: 3.8
|
||||
addToPath: true
|
||||
- script: |
|
||||
set -e
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends nginx-light snapd
|
||||
python3 -m venv venv
|
||||
venv/bin/python tools/pipstrap.py
|
||||
venv/bin/python tools/pip_install.py -U tox
|
||||
displayName: Install dependencies
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: snaps
|
||||
path: $(Build.SourcesDirectory)/snap
|
||||
displayName: Retrieve Certbot snaps
|
||||
- script: |
|
||||
set -e
|
||||
sudo snap install --dangerous --classic snap/certbot_*_amd64.snap
|
||||
displayName: Install Certbot snap
|
||||
- script: |
|
||||
set -e
|
||||
venv/bin/python -m tox -e integration-external,apacheconftest-external-with-pebble
|
||||
displayName: Run tox
|
||||
- job: snap_dns_run
|
||||
dependsOn: snaps_build
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
steps:
|
||||
- script: |
|
||||
set -e
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends snapd
|
||||
displayName: Install dependencies
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: 3.8
|
||||
addToPath: true
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: snaps
|
||||
path: $(Build.SourcesDirectory)/snap
|
||||
displayName: Retrieve Certbot snaps
|
||||
- script: |
|
||||
set -e
|
||||
python3 -m venv venv
|
||||
venv/bin/python tools/pipstrap.py
|
||||
venv/bin/python tools/pip_install.py -e certbot-ci
|
||||
displayName: Prepare Certbot-CI
|
||||
- script: |
|
||||
set -e
|
||||
sudo -E venv/bin/pytest certbot-ci/snap_integration_tests/dns_tests --allow-persistent-changes --snap-folder $(Build.SourcesDirectory)/snap --snap-arch amd64
|
||||
displayName: Test DNS plugins snaps
|
||||
|
||||
@@ -4,10 +4,10 @@ jobs:
|
||||
PYTHON_VERSION: 3.9
|
||||
strategy:
|
||||
matrix:
|
||||
macos-py36:
|
||||
macos-py27:
|
||||
IMAGE_NAME: macOS-10.15
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: py36
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: py27
|
||||
macos-py39:
|
||||
IMAGE_NAME: macOS-10.15
|
||||
PYTHON_VERSION: 3.9
|
||||
@@ -16,22 +16,24 @@ jobs:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: py36
|
||||
windows-py38-cover:
|
||||
windows-py37-cover:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.8
|
||||
TOXENV: py38-cover
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: py37-cover
|
||||
windows-integration-certbot:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.8
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: integration-certbot
|
||||
linux-oldest-tests-1:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: '{acme,apache,apache-v2,certbot}-oldest'
|
||||
TOXENV: py27-{acme,apache,apache-v2,certbot}-oldest
|
||||
linux-oldest-tests-2:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: '{dns,nginx}-oldest'
|
||||
TOXENV: py27-{dns,nginx}-oldest
|
||||
linux-py27:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: py27
|
||||
linux-py36:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.6
|
||||
@@ -61,18 +63,13 @@ jobs:
|
||||
TOXENV: modification
|
||||
apacheconftest:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.6
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: apacheconftest-with-pebble
|
||||
nginxroundtrip:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.6
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: nginxroundtrip
|
||||
pool:
|
||||
vmImage: $(IMAGE_NAME)
|
||||
steps:
|
||||
- template: ../steps/tox-steps.yml
|
||||
- job: test_sphinx_builds
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- template: ../steps/sphinx-steps.yml
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
stages:
|
||||
- stage: TestAndPackage
|
||||
jobs:
|
||||
- template: ../jobs/standard-tests-jobs.yml
|
||||
- template: ../jobs/extended-tests-jobs.yml
|
||||
- template: ../jobs/packaging-jobs.yml
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
steps:
|
||||
- bash: |
|
||||
FINAL_STATUS=0
|
||||
declare -a FAILED_BUILDS
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python tools/pipstrap.py
|
||||
for doc_path in */docs
|
||||
do
|
||||
echo ""
|
||||
echo "##[group]Building $doc_path"
|
||||
pip install -q -e $doc_path/..[docs]
|
||||
if ! sphinx-build -W --keep-going -b html $doc_path $doc_path/_build/html; then
|
||||
FINAL_STATUS=1
|
||||
FAILED_BUILDS[${#FAILED_BUILDS[@]}]="${doc_path%/docs}"
|
||||
fi
|
||||
echo "##[endgroup]"
|
||||
done
|
||||
if [[ $FINAL_STATUS -ne 0 ]]; then
|
||||
echo "##[error]The following builds failed: ${FAILED_BUILDS[*]}"
|
||||
exit 1
|
||||
fi
|
||||
displayName: Build Sphinx Documentation
|
||||
@@ -45,7 +45,11 @@ steps:
|
||||
export TARGET_BRANCH="`echo "${BUILD_SOURCEBRANCH}" | sed -E 's!refs/(heads|tags)/!!g'`"
|
||||
[ -z "${SYSTEM_PULLREQUEST_TARGETBRANCH}" ] || export TARGET_BRANCH="${SYSTEM_PULLREQUEST_TARGETBRANCH}"
|
||||
env
|
||||
python -m tox
|
||||
if [[ "${TOXENV}" == *"oldest"* ]]; then
|
||||
tools/run_oldest_tests.sh
|
||||
else
|
||||
python -m tox
|
||||
fi
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID)
|
||||
AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
Authors
|
||||
=======
|
||||
|
||||
* [Aaron Gable](https://github.com/aarongable)
|
||||
* [Aaron Zirbes](https://github.com/aaronzirbes)
|
||||
* Aaron Zuehlke
|
||||
* Ada Lovelace
|
||||
@@ -61,7 +60,6 @@ Authors
|
||||
* [DanCld](https://github.com/DanCld)
|
||||
* [Daniel Albers](https://github.com/AID)
|
||||
* [Daniel Aleksandersen](https://github.com/da2x)
|
||||
* [Daniel Almasi](https://github.com/almasen)
|
||||
* [Daniel Convissor](https://github.com/convissor)
|
||||
* [Daniel "Drex" Drexler](https://github.com/aeturnum)
|
||||
* [Daniel Huang](https://github.com/dhuang)
|
||||
@@ -151,7 +149,6 @@ Authors
|
||||
* [Lior Sabag](https://github.com/liorsbg)
|
||||
* [Lipis](https://github.com/lipis)
|
||||
* [lord63](https://github.com/lord63)
|
||||
* [Lorenzo Fundaró](https://github.com/lfundaro)
|
||||
* [Luca Beltrame](https://github.com/lbeltrame)
|
||||
* [Luca Ebach](https://github.com/lucebac)
|
||||
* [Luca Olivetti](https://github.com/olivluca)
|
||||
|
||||
@@ -6,6 +6,7 @@ This module is an implementation of the `ACME protocol`_.
|
||||
|
||||
"""
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
# This code exists to keep backwards compatibility with people using acme.jose
|
||||
# before it became the standalone josepy package.
|
||||
@@ -19,3 +20,10 @@ for mod in list(sys.modules):
|
||||
# preserved (acme.jose.* is josepy.*)
|
||||
if mod == 'josepy' or mod.startswith('josepy.'):
|
||||
sys.modules['acme.' + mod.replace('josepy', 'jose', 1)] = sys.modules[mod]
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
warnings.warn(
|
||||
"Python 2 support will be dropped in the next release of acme. "
|
||||
"Please upgrade your Python version.",
|
||||
PendingDeprecationWarning,
|
||||
) # pragma: no cover
|
||||
|
||||
@@ -150,7 +150,7 @@ class KeyAuthorizationChallenge(_TokenChallenge):
|
||||
"""Challenge based on Key Authorization.
|
||||
|
||||
:param response_cls: Subclass of `KeyAuthorizationChallengeResponse`
|
||||
that will be used to generate ``response``.
|
||||
that will be used to generate `response`.
|
||||
:param str typ: type of the challenge
|
||||
"""
|
||||
typ = NotImplemented
|
||||
|
||||
@@ -166,7 +166,7 @@ def probe_sni(name, host, port=443, timeout=300, # pylint: disable=too-many-argu
|
||||
" from {0}:{1}".format(
|
||||
source_address[0],
|
||||
source_address[1]
|
||||
) if any(source_address) else ""
|
||||
) if socket_kwargs else ""
|
||||
)
|
||||
socket_tuple = (host, port) # type: Tuple[str, int]
|
||||
sock = socket.create_connection(socket_tuple, **socket_kwargs) # type: ignore
|
||||
@@ -186,7 +186,6 @@ def probe_sni(name, host, port=443, timeout=300, # pylint: disable=too-many-argu
|
||||
raise errors.Error(error)
|
||||
return client_ssl.get_peer_certificate()
|
||||
|
||||
|
||||
def make_csr(private_key_pem, domains, must_staple=False):
|
||||
"""Generate a CSR containing a list of domains as subjectAltNames.
|
||||
|
||||
@@ -218,7 +217,6 @@ def make_csr(private_key_pem, domains, must_staple=False):
|
||||
return crypto.dump_certificate_request(
|
||||
crypto.FILETYPE_PEM, csr)
|
||||
|
||||
|
||||
def _pyopenssl_cert_or_req_all_names(loaded_cert_or_req):
|
||||
common_name = loaded_cert_or_req.get_subject().CN
|
||||
sans = _pyopenssl_cert_or_req_san(loaded_cert_or_req)
|
||||
@@ -227,7 +225,6 @@ def _pyopenssl_cert_or_req_all_names(loaded_cert_or_req):
|
||||
return sans
|
||||
return [common_name] + [d for d in sans if d != common_name]
|
||||
|
||||
|
||||
def _pyopenssl_cert_or_req_san(cert_or_req):
|
||||
"""Get Subject Alternative Names from certificate or CSR using pyOpenSSL.
|
||||
|
||||
@@ -320,7 +317,6 @@ def gen_ss_cert(key, domains, not_before=None,
|
||||
cert.sign(key, "sha256")
|
||||
return cert
|
||||
|
||||
|
||||
def dump_pyopenssl_chain(chain, filetype=crypto.FILETYPE_PEM):
|
||||
"""Dump certificate chain into a bundle.
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class MissingNonce(NonceError):
|
||||
Replay-Nonce header field in each successful response to a POST it
|
||||
provides to a client (...)".
|
||||
|
||||
:ivar requests.Response ~.response: HTTP Response
|
||||
:ivar requests.Response response: HTTP Response
|
||||
|
||||
"""
|
||||
def __init__(self, response, *args, **kwargs):
|
||||
|
||||
@@ -275,7 +275,7 @@ class Resource(jose.JSONObjectWithFields):
|
||||
class ResourceWithURI(Resource):
|
||||
"""ACME Resource with URI.
|
||||
|
||||
:ivar unicode ~.uri: Location of the resource.
|
||||
:ivar unicode uri: Location of the resource.
|
||||
|
||||
"""
|
||||
uri = jose.Field('uri') # no ChallengeResource.uri
|
||||
@@ -627,7 +627,7 @@ class Order(ResourceBody):
|
||||
:ivar str finalize: URL to POST to to request issuance once all
|
||||
authorizations have "valid" status.
|
||||
:ivar datetime.datetime expires: When the order expires.
|
||||
:ivar ~.Error error: Any error that occurred during finalization, if applicable.
|
||||
: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,
|
||||
|
||||
@@ -85,10 +85,7 @@ language = 'en'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = [
|
||||
'_build',
|
||||
'man/*'
|
||||
]
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
|
||||
@@ -5,22 +5,25 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'cryptography>=2.1.4',
|
||||
# load_pem_private/public_key (>=0.6)
|
||||
# rsa_recover_prime_factors (>=0.8)
|
||||
'cryptography>=1.2.3',
|
||||
# formerly known as acme.jose:
|
||||
# 1.1.0+ is required to avoid the warnings described at
|
||||
# https://github.com/certbot/josepy/issues/13.
|
||||
'josepy>=1.1.0',
|
||||
'PyOpenSSL>=17.3.0',
|
||||
# Connection.set_tlsext_host_name (>=0.13) + matching Xenial requirements (>=0.15.1)
|
||||
'PyOpenSSL>=0.15.1',
|
||||
'pyrfc3339',
|
||||
'pytz',
|
||||
'requests[security]>=2.6.0', # security extras added in 2.4.1
|
||||
'requests-toolbelt>=0.3.0',
|
||||
'setuptools>=39.0.1',
|
||||
'six>=1.11.0',
|
||||
'setuptools',
|
||||
'six>=1.9.0', # needed for python_2_unicode_compatible
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
@@ -51,12 +54,14 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -14,10 +14,10 @@ class OpenSUSEConfigurator(configurator.ApacheConfigurator):
|
||||
vhost_root="/etc/apache2/vhosts.d",
|
||||
vhost_files="*.conf",
|
||||
logs_root="/var/log/apache2",
|
||||
ctl="apachectl",
|
||||
version_cmd=['apachectl', '-v'],
|
||||
restart_cmd=['apachectl', 'graceful'],
|
||||
conftest_cmd=['apachectl', 'configtest'],
|
||||
ctl="apache2ctl",
|
||||
version_cmd=['apache2ctl', '-v'],
|
||||
restart_cmd=['apache2ctl', 'graceful'],
|
||||
conftest_cmd=['apache2ctl', 'configtest'],
|
||||
enmod="a2enmod",
|
||||
dismod="a2dismod",
|
||||
le_vhost_ext="-le-ssl.conf",
|
||||
|
||||
@@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
@@ -13,7 +13,7 @@ install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.6.0',
|
||||
'python-augeas',
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.component',
|
||||
'zope.interface',
|
||||
]
|
||||
@@ -39,7 +39,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -47,6 +47,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
48
certbot-auto
48
certbot-auto
@@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
|
||||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
|
||||
LE_AUTO_VERSION="1.11.0"
|
||||
LE_AUTO_VERSION="1.10.1"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
@@ -804,7 +804,6 @@ elif [ -f /etc/mageia-release ]; then
|
||||
# Mageia has both /etc/mageia-release and /etc/redhat-release
|
||||
DEPRECATED_OS=1
|
||||
elif [ -f /etc/redhat-release ]; then
|
||||
DEPRECATED_OS=1
|
||||
# Run DeterminePythonVersion to decide on the basis of available Python versions
|
||||
# whether to use 2.x or 3.x on RedHat-like systems.
|
||||
# Then, revert LE_PYTHON to its previous state.
|
||||
@@ -837,7 +836,12 @@ elif [ -f /etc/redhat-release ]; then
|
||||
INTERACTIVE_BOOTSTRAP=1
|
||||
fi
|
||||
|
||||
Bootstrap() {
|
||||
BootstrapMessage "Legacy RedHat-based OSes that will use Python3"
|
||||
BootstrapRpmPython3Legacy
|
||||
}
|
||||
USE_PYTHON_3=1
|
||||
BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION"
|
||||
|
||||
# Try now to enable SCL rh-python36 for systems already bootstrapped
|
||||
# NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto
|
||||
@@ -856,7 +860,18 @@ elif [ -f /etc/redhat-release ]; then
|
||||
fi
|
||||
|
||||
if [ "$RPM_USE_PYTHON_3" = 1 ]; then
|
||||
Bootstrap() {
|
||||
BootstrapMessage "RedHat-based OSes that will use Python3"
|
||||
BootstrapRpmPython3
|
||||
}
|
||||
USE_PYTHON_3=1
|
||||
BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION"
|
||||
else
|
||||
Bootstrap() {
|
||||
BootstrapMessage "RedHat-based OSes"
|
||||
BootstrapRpmCommon
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -874,7 +889,10 @@ elif uname | grep -iq FreeBSD ; then
|
||||
elif uname | grep -iq Darwin ; then
|
||||
DEPRECATED_OS=1
|
||||
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
|
||||
DEPRECATED_OS=1
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
|
||||
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
|
||||
DEPRECATED_OS=1
|
||||
else
|
||||
@@ -1475,18 +1493,18 @@ letsencrypt==0.7.0 \
|
||||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==1.11.0 \
|
||||
--hash=sha256:b7faa66c40a1ce5a31bfc8668d8feb5d2db6f7af9e791079a6d95c77b6593bf4 \
|
||||
--hash=sha256:6b0ce04e55379aff0a47f873fa05c084538ad0f4a9b79f33108dbb0a7a668b43
|
||||
acme==1.11.0 \
|
||||
--hash=sha256:77d6ce61b155315d7d7031489bbd245c0ea42c0453a04d4304393414e741a56d \
|
||||
--hash=sha256:092eb09a074a935da4c10f66cb8634ffb2cc2d2cc1035d2998d608996efab924
|
||||
certbot-apache==1.11.0 \
|
||||
--hash=sha256:ea7ac88733aad91a89c700289effda2a0c0658778da1ae2c54a0aefaee351285 \
|
||||
--hash=sha256:3ed001427ec0b49324f2b9af7170fa6e6e88948fa51c3678b07bf17f8138863d
|
||||
certbot-nginx==1.11.0 \
|
||||
--hash=sha256:79de69782a1199e577787ff9790dee02a44aac17dbecd6a7287593030842a306 \
|
||||
--hash=sha256:9afe611f99a78b8898941b8ad7bdcf7f3c2b6e0fce27125268f7c713e64b34ee
|
||||
certbot==1.10.1 \
|
||||
--hash=sha256:011ac980fa21b9f29e02c9b8d8b86e8a4bf4670b51b6ad91656e401e9d2d2231 \
|
||||
--hash=sha256:0d9ee3fc09e0d03b2d1b1f1c4916e61ecfc6904b4216ddef4e6a5ca1424d9cb7
|
||||
acme==1.10.1 \
|
||||
--hash=sha256:752d598e54e98ad1e874de53fd50c61044f1b566d6deb790db5676ce9c573546 \
|
||||
--hash=sha256:fcbb559aedc96b404edf593e78517dcd7291984d5a37036c3fc77f3c5c122fd8
|
||||
certbot-apache==1.10.1 \
|
||||
--hash=sha256:f077b4b7f166627ef5e0921fe7cde57700670fc86e9ad9dbdfaf2c573cc0f2fa \
|
||||
--hash=sha256:97ed637b4c7b03820db6c69aa90145dc989933351d46a3d62baf6b71674f0a10
|
||||
certbot-nginx==1.10.1 \
|
||||
--hash=sha256:7c36459021f8a1ec3b6c062e4c4fc866bfaa1dbf26ccd29e043dd6848003be08 \
|
||||
--hash=sha256:c0bbeccf85f46b728fd95e6bb8c2649d32d3383d7f47ea4b9c312d12bf04d2f0
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# pylint: disable=missing-module-docstring
|
||||
import pytest
|
||||
|
||||
# Custom assertions defined in the following package need to be registered to be properly
|
||||
|
||||
@@ -77,6 +77,6 @@ class IntegrationTestsContext(object):
|
||||
appending the pytest worker id to the subdomain, using this pattern:
|
||||
{subdomain}.{worker_id}.wtf
|
||||
:param subdomain: the subdomain to use in the generated domain (default 'le')
|
||||
:return: the well-formed domain suitable for redirection on
|
||||
:return: the well-formed domain suitable for redirection on
|
||||
"""
|
||||
return '{0}.{1}.wtf'.format(subdomain, self.worker_id)
|
||||
|
||||
@@ -9,7 +9,7 @@ import shutil
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1, SECP384R1, SECP521R1
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1, SECP384R1
|
||||
from cryptography.x509 import NameOID
|
||||
|
||||
import pytest
|
||||
@@ -29,9 +29,8 @@ from certbot_integration_tests.certbot_tests.assertions import EVERYBODY_SID
|
||||
from certbot_integration_tests.utils import misc
|
||||
|
||||
|
||||
@pytest.fixture(name='context')
|
||||
def test_context(request):
|
||||
# pylint: disable=missing-function-docstring
|
||||
@pytest.fixture()
|
||||
def context(request):
|
||||
# Fixture request is a built-in pytest fixture describing current test request.
|
||||
integration_test_context = certbot_context.IntegrationTestsContext(request)
|
||||
try:
|
||||
@@ -148,17 +147,6 @@ def test_certonly(context):
|
||||
"""Test the certonly verb on certbot."""
|
||||
context.certbot(['certonly', '--cert-name', 'newname', '-d', context.get_domain('newname')])
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, 'newname', 1)
|
||||
|
||||
|
||||
def test_certonly_webroot(context):
|
||||
"""Test the certonly verb with webroot plugin"""
|
||||
with misc.create_http_server(context.http_01_port) as webroot:
|
||||
certname = context.get_domain('webroot')
|
||||
context.certbot(['certonly', '-a', 'webroot', '--webroot-path', webroot, '-d', certname])
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||
|
||||
|
||||
def test_auth_and_install_with_csr(context):
|
||||
"""Test certificate issuance and install using an existing CSR."""
|
||||
@@ -234,16 +222,14 @@ def test_renew_files_propagate_permissions(context):
|
||||
if os.name != 'nt':
|
||||
os.chmod(privkey1, 0o444)
|
||||
else:
|
||||
import win32security # pylint: disable=import-error
|
||||
import ntsecuritycon # pylint: disable=import-error
|
||||
import win32security
|
||||
import ntsecuritycon
|
||||
# Get the current DACL of the private key
|
||||
security = win32security.GetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION)
|
||||
dacl = security.GetSecurityDescriptorDacl()
|
||||
# Create a read permission for Everybody group
|
||||
everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)
|
||||
dacl.AddAccessAllowedAce(
|
||||
win32security.ACL_REVISION, ntsecuritycon.FILE_GENERIC_READ, everybody
|
||||
)
|
||||
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, ntsecuritycon.FILE_GENERIC_READ, everybody)
|
||||
# Apply the updated DACL to the private key
|
||||
security.SetSecurityDescriptorDacl(1, dacl, 0)
|
||||
win32security.SetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION, security)
|
||||
@@ -252,14 +238,12 @@ def test_renew_files_propagate_permissions(context):
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||
if os.name != 'nt':
|
||||
# On Linux, read world permissions + all group permissions
|
||||
# will be copied from the previous private key
|
||||
# On Linux, read world permissions + all group permissions will be copied from the previous private key
|
||||
assert_world_read_permissions(privkey2)
|
||||
assert_equals_world_read_permissions(privkey1, privkey2)
|
||||
assert_equals_group_permissions(privkey1, privkey2)
|
||||
else:
|
||||
# On Windows, world will never have any permissions, and
|
||||
# group permission is irrelevant for this platform
|
||||
# On Windows, world will never have any permissions, and group permission is irrelevant for this platform
|
||||
assert_world_no_permissions(privkey2)
|
||||
|
||||
|
||||
@@ -487,28 +471,6 @@ def test_default_curve_type(context):
|
||||
assert_elliptic_key(key1, SECP256R1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('curve,curve_cls,skip_servers', [
|
||||
# Curve name, Curve class, ACME servers to skip
|
||||
('secp256r1', SECP256R1, []),
|
||||
('secp384r1', SECP384R1, []),
|
||||
('secp521r1', SECP521R1, ['boulder-v1', 'boulder-v2'])]
|
||||
)
|
||||
def test_ecdsa_curves(context, curve, curve_cls, skip_servers):
|
||||
"""Test issuance for each supported ECDSA curve"""
|
||||
if context.acme_server in skip_servers:
|
||||
pytest.skip('ACME server {} does not support ECDSA curve {}'
|
||||
.format(context.acme_server, curve))
|
||||
|
||||
domain = context.get_domain('curve')
|
||||
context.certbot([
|
||||
'certonly',
|
||||
'--key-type', 'ecdsa', '--elliptic-curve', curve,
|
||||
'--force-renewal', '-d', domain,
|
||||
])
|
||||
key = join(context.config_dir, "live", domain, 'privkey.pem')
|
||||
assert_elliptic_key(key, curve_cls)
|
||||
|
||||
|
||||
def test_renew_with_ec_keys(context):
|
||||
"""Test proper renew with updated private key complexity."""
|
||||
certname = context.get_domain('renew')
|
||||
@@ -647,22 +609,19 @@ def test_revoke_multiple_lineages(context):
|
||||
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(cert2)), 'r') as file:
|
||||
data = file.read()
|
||||
|
||||
data = re.sub(
|
||||
'archive_dir = .*\n',
|
||||
'archive_dir = {0}\n'.format(
|
||||
join(context.config_dir, 'archive', cert1).replace('\\', '\\\\')
|
||||
), data
|
||||
)
|
||||
data = re.sub('archive_dir = .*\n',
|
||||
'archive_dir = {0}\n'.format(join(context.config_dir, 'archive', cert1).replace('\\', '\\\\')),
|
||||
data)
|
||||
|
||||
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(cert2)), 'w') as file:
|
||||
file.write(data)
|
||||
|
||||
context.certbot([
|
||||
output = context.certbot([
|
||||
'revoke', '--cert-path', join(context.config_dir, 'live', cert1, 'cert.pem')
|
||||
])
|
||||
|
||||
with open(join(context.workspace, 'logs', 'letsencrypt.log'), 'r') as f:
|
||||
assert 'Not deleting revoked certificates due to overlapping archive dirs' in f.read()
|
||||
assert 'Not deleting revoked certs due to overlapping archive dirs' in f.read()
|
||||
|
||||
|
||||
def test_wildcard_certificates(context):
|
||||
|
||||
@@ -13,6 +13,7 @@ import sys
|
||||
|
||||
from certbot_integration_tests.utils import acme_server as acme_lib
|
||||
from certbot_integration_tests.utils import dns_server as dns_lib
|
||||
from certbot_integration_tests.utils.dns_server import DNSServer
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
@@ -91,10 +92,8 @@ def _setup_primary_node(config):
|
||||
try:
|
||||
subprocess.check_output(['docker-compose', '-v'], stderr=subprocess.STDOUT)
|
||||
except (subprocess.CalledProcessError, OSError):
|
||||
raise ValueError(
|
||||
'Error: docker-compose is required in PATH to launch the integration tests, '
|
||||
'but is not installed or not available for current user.'
|
||||
)
|
||||
raise ValueError('Error: docker-compose is required in PATH to launch the integration tests, '
|
||||
'but is not installed or not available for current user.')
|
||||
|
||||
# Parameter numprocesses is added to option by pytest-xdist
|
||||
workers = ['primary'] if not config.option.numprocesses\
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
"""Module to handle the context of nginx integration tests."""
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
import os
|
||||
import ssl
|
||||
|
||||
from typing import List
|
||||
import pytest
|
||||
|
||||
from certbot_integration_tests.nginx_tests import context as nginx_context
|
||||
|
||||
|
||||
@pytest.fixture(name='context')
|
||||
def test_context(request):
|
||||
@pytest.fixture()
|
||||
def context(request):
|
||||
# Fixture request is a built-in pytest fixture describing current test request.
|
||||
integration_test_context = nginx_context.IntegrationTestsContext(request)
|
||||
try:
|
||||
@@ -28,12 +27,10 @@ def test_context(request):
|
||||
# No matching server block; default_server does not exist
|
||||
('nginx5.{0}.wtf', ['--preferred-challenges', 'http'], {'default_server': False}),
|
||||
# Multiple domains, mix of matching and not
|
||||
('nginx6.{0}.wtf,nginx7.{0}.wtf', [
|
||||
'--preferred-challenges', 'http'
|
||||
], {'default_server': False}),
|
||||
('nginx6.{0}.wtf,nginx7.{0}.wtf', ['--preferred-challenges', 'http'], {'default_server': False}),
|
||||
], indirect=['context'])
|
||||
def test_certificate_deployment(certname_pattern, params, context):
|
||||
# type: (str, List[str], nginx_context.IntegrationTestsContext) -> None
|
||||
# type: (str, list, nginx_context.IntegrationTestsContext) -> None
|
||||
"""
|
||||
Test various scenarios to deploy a certificate to nginx using certbot.
|
||||
"""
|
||||
@@ -44,9 +41,7 @@ def test_certificate_deployment(certname_pattern, params, context):
|
||||
|
||||
lineage = domains.split(',')[0]
|
||||
server_cert = ssl.get_server_certificate(('localhost', context.tls_alpn_01_port))
|
||||
with open(os.path.join(
|
||||
context.workspace, 'conf/live/{0}/cert.pem'.format(lineage)), 'r'
|
||||
) as file:
|
||||
with open(os.path.join(context.workspace, 'conf/live/{0}/cert.pem'.format(lineage)), 'r') as file:
|
||||
certbot_cert = file.read()
|
||||
|
||||
assert server_cert == certbot_cert
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
"""Module to handle the context of RFC2136 integration tests."""
|
||||
|
||||
import tempfile
|
||||
from contextlib import contextmanager
|
||||
|
||||
from pkg_resources import resource_filename
|
||||
from pytest import skip
|
||||
from pkg_resources import resource_filename
|
||||
import tempfile
|
||||
|
||||
from certbot_integration_tests.certbot_tests import context as certbot_context
|
||||
from certbot_integration_tests.utils import certbot_call
|
||||
@@ -36,6 +33,7 @@ class IntegrationTestsContext(certbot_context.IntegrationTestsContext):
|
||||
|
||||
@contextmanager
|
||||
def rfc2136_credentials(self, label='default'):
|
||||
# type: (str) -> str
|
||||
"""
|
||||
Produces the contents of a certbot-dns-rfc2136 credentials file.
|
||||
:param str label: which RFC2136 credential to use
|
||||
@@ -54,10 +52,10 @@ class IntegrationTestsContext(certbot_context.IntegrationTestsContext):
|
||||
)
|
||||
|
||||
with tempfile.NamedTemporaryFile('w+', prefix='rfc2136-creds-{}'.format(label),
|
||||
suffix='.ini', dir=self.workspace) as fp:
|
||||
fp.write(contents)
|
||||
fp.flush()
|
||||
yield fp.name
|
||||
suffix='.ini', dir=self.workspace) as f:
|
||||
f.write(contents)
|
||||
f.flush()
|
||||
yield f.name
|
||||
|
||||
def skip_if_no_bind9_server(self):
|
||||
"""Skips the test if there was no RFC2136-capable DNS server configured
|
||||
|
||||
@@ -4,9 +4,8 @@ import pytest
|
||||
from certbot_integration_tests.rfc2136_tests import context as rfc2136_context
|
||||
|
||||
|
||||
@pytest.fixture(name="context")
|
||||
def pytest_context(request):
|
||||
# pylint: disable=missing-function-docstring
|
||||
@pytest.fixture()
|
||||
def context(request):
|
||||
# Fixture request is a built-in pytest fixture describing current test request.
|
||||
integration_test_context = rfc2136_context.IntegrationTestsContext(request)
|
||||
try:
|
||||
|
||||
@@ -7,19 +7,18 @@ import errno
|
||||
import json
|
||||
import os
|
||||
from os.path import join
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from typing import List
|
||||
import requests
|
||||
|
||||
from certbot_integration_tests.utils import misc
|
||||
from certbot_integration_tests.utils import pebble_artifacts
|
||||
from certbot_integration_tests.utils import proxy
|
||||
# pylint: disable=wildcard-import,unused-wildcard-import
|
||||
from certbot_integration_tests.utils.constants import *
|
||||
|
||||
|
||||
@@ -32,11 +31,10 @@ class ACMEServer(object):
|
||||
ACMEServer gives access the acme_xdist parameter, listing the ports and directory url to use
|
||||
for each pytest node. It exposes also start and stop methods in order to start the stack, and
|
||||
stop it with proper resources cleanup.
|
||||
ACMEServer is also a context manager, and so can be used to ensure ACME server is
|
||||
started/stopped upon context enter/exit.
|
||||
ACMEServer is also a context manager, and so can be used to ensure ACME server is started/stopped
|
||||
upon context enter/exit.
|
||||
"""
|
||||
def __init__(self, acme_server, nodes, http_proxy=True, stdout=False,
|
||||
dns_server=None, http_01_port=DEFAULT_HTTP_01_PORT):
|
||||
def __init__(self, acme_server, nodes, http_proxy=True, stdout=False, dns_server=None):
|
||||
"""
|
||||
Create an ACMEServer instance.
|
||||
:param str acme_server: the type of acme server used (boulder-v1, boulder-v2 or pebble)
|
||||
@@ -44,22 +42,15 @@ class ACMEServer(object):
|
||||
:param bool http_proxy: if False do not start the HTTP proxy
|
||||
:param bool stdout: if True stream all subprocesses stdout to standard stdout
|
||||
:param str dns_server: if set, Pebble/Boulder will use it to resolve domains
|
||||
:param int http_01_port: port to use for http-01 validation; currently
|
||||
only supported for pebble without an HTTP proxy
|
||||
"""
|
||||
self._construct_acme_xdist(acme_server, nodes)
|
||||
|
||||
self._acme_type = 'pebble' if acme_server == 'pebble' else 'boulder'
|
||||
self._proxy = http_proxy
|
||||
self._workspace = tempfile.mkdtemp()
|
||||
self._processes = [] # type: List[subprocess.Popen]
|
||||
self._processes = []
|
||||
self._stdout = sys.stdout if stdout else open(os.devnull, 'w')
|
||||
self._dns_server = dns_server
|
||||
self._http_01_port = http_01_port
|
||||
if http_01_port != DEFAULT_HTTP_01_PORT:
|
||||
if self._acme_type != 'pebble' or self._proxy:
|
||||
raise ValueError('setting http_01_port is not currently supported '
|
||||
'with boulder or the HTTP proxy')
|
||||
|
||||
def start(self):
|
||||
"""Start the test stack"""
|
||||
@@ -116,34 +107,26 @@ class ACMEServer(object):
|
||||
"""Generate and return the acme_xdist dict"""
|
||||
acme_xdist = {'acme_server': acme_server, 'challtestsrv_port': CHALLTESTSRV_PORT}
|
||||
|
||||
# Directory and ACME port are set implicitly in the docker-compose.yml
|
||||
# files of Boulder/Pebble.
|
||||
# Directory and ACME port are set implicitly in the docker-compose.yml files of Boulder/Pebble.
|
||||
if acme_server == 'pebble':
|
||||
acme_xdist['directory_url'] = PEBBLE_DIRECTORY_URL
|
||||
else: # boulder
|
||||
acme_xdist['directory_url'] = BOULDER_V2_DIRECTORY_URL \
|
||||
if acme_server == 'boulder-v2' else BOULDER_V1_DIRECTORY_URL
|
||||
|
||||
acme_xdist['http_port'] = {
|
||||
node: port for (node, port) in # pylint: disable=unnecessary-comprehension
|
||||
zip(nodes, range(5200, 5200 + len(nodes)))
|
||||
}
|
||||
acme_xdist['https_port'] = {
|
||||
node: port for (node, port) in # pylint: disable=unnecessary-comprehension
|
||||
zip(nodes, range(5100, 5100 + len(nodes)))
|
||||
}
|
||||
acme_xdist['other_port'] = {
|
||||
node: port for (node, port) in # pylint: disable=unnecessary-comprehension
|
||||
zip(nodes, range(5300, 5300 + len(nodes)))
|
||||
}
|
||||
acme_xdist['http_port'] = {node: port for (node, port)
|
||||
in zip(nodes, range(5200, 5200 + len(nodes)))}
|
||||
acme_xdist['https_port'] = {node: port for (node, port)
|
||||
in zip(nodes, range(5100, 5100 + len(nodes)))}
|
||||
acme_xdist['other_port'] = {node: port for (node, port)
|
||||
in zip(nodes, range(5300, 5300 + len(nodes)))}
|
||||
|
||||
self.acme_xdist = acme_xdist
|
||||
|
||||
def _prepare_pebble_server(self):
|
||||
"""Configure and launch the Pebble server"""
|
||||
print('=> Starting pebble instance deployment...')
|
||||
pebble_artifacts_rv = pebble_artifacts.fetch(self._workspace, self._http_01_port)
|
||||
pebble_path, challtestsrv_path, pebble_config_path = pebble_artifacts_rv
|
||||
pebble_path, challtestsrv_path, pebble_config_path = pebble_artifacts.fetch(self._workspace)
|
||||
|
||||
# Configure Pebble at full speed (PEBBLE_VA_NOSLEEP=1) and not randomly refusing valid
|
||||
# nonce (PEBBLE_WFE_NONCEREJECT=0) to have a stable test environment.
|
||||
@@ -167,9 +150,9 @@ class ACMEServer(object):
|
||||
env=environ)
|
||||
|
||||
# pebble_ocsp_server is imported here and not at the top of module in order to avoid a
|
||||
# useless ImportError, in the case where cryptography dependency is too old to support
|
||||
# ocsp, but Boulder is used instead of Pebble, so pebble_ocsp_server is not used. This is
|
||||
# the typical situation of integration-certbot-oldest tox testenv.
|
||||
# useless ImportError, in the case where cryptography dependency is too old to support ocsp,
|
||||
# but Boulder is used instead of Pebble, so pebble_ocsp_server is not used. This is the
|
||||
# typical situation of integration-certbot-oldest tox testenv.
|
||||
from certbot_integration_tests.utils import pebble_ocsp_server
|
||||
self._launch_process([sys.executable, pebble_ocsp_server.__file__])
|
||||
|
||||
@@ -212,16 +195,13 @@ class ACMEServer(object):
|
||||
|
||||
if not self._dns_server:
|
||||
# Configure challtestsrv to answer any A record request with ip of the docker host.
|
||||
response = requests.post('http://localhost:{0}/set-default-ipv4'.format(
|
||||
CHALLTESTSRV_PORT), json={'ip': '10.77.77.1'}
|
||||
)
|
||||
response = requests.post('http://localhost:{0}/set-default-ipv4'.format(CHALLTESTSRV_PORT),
|
||||
json={'ip': '10.77.77.1'})
|
||||
response.raise_for_status()
|
||||
except BaseException:
|
||||
# If we failed to set up boulder, print its logs.
|
||||
print('=> Boulder setup failed. Boulder logs are:')
|
||||
process = self._launch_process([
|
||||
'docker-compose', 'logs'], cwd=instance_path, force_stderr=True
|
||||
)
|
||||
process = self._launch_process(['docker-compose', 'logs'], cwd=instance_path, force_stderr=True)
|
||||
process.wait()
|
||||
raise
|
||||
|
||||
@@ -232,7 +212,7 @@ class ACMEServer(object):
|
||||
print('=> Configuring the HTTP proxy...')
|
||||
mapping = {r'.+\.{0}\.wtf'.format(node): 'http://127.0.0.1:{0}'.format(port)
|
||||
for node, port in self.acme_xdist['http_port'].items()}
|
||||
command = [sys.executable, proxy.__file__, str(DEFAULT_HTTP_01_PORT), json.dumps(mapping)]
|
||||
command = [sys.executable, proxy.__file__, str(HTTP_01_PORT), json.dumps(mapping)]
|
||||
self._launch_process(command)
|
||||
print('=> Finished configuring the HTTP proxy.')
|
||||
|
||||
@@ -241,15 +221,12 @@ class ACMEServer(object):
|
||||
if not env:
|
||||
env = os.environ
|
||||
stdout = sys.stderr if force_stderr else self._stdout
|
||||
process = subprocess.Popen(
|
||||
command, stdout=stdout, stderr=subprocess.STDOUT, cwd=cwd, env=env
|
||||
)
|
||||
process = subprocess.Popen(command, stdout=stdout, stderr=subprocess.STDOUT, cwd=cwd, env=env)
|
||||
self._processes.append(process)
|
||||
return process
|
||||
|
||||
|
||||
def main():
|
||||
# pylint: disable=missing-function-docstring
|
||||
parser = argparse.ArgumentParser(
|
||||
description='CLI tool to start a local instance of Pebble or Boulder CA server.')
|
||||
parser.add_argument('--server-type', '-s',
|
||||
@@ -260,15 +237,9 @@ def main():
|
||||
help='specify the DNS server as `IP:PORT` to use by '
|
||||
'Pebble; if not specified, a local mock DNS server will be used to '
|
||||
'resolve domains to localhost.')
|
||||
parser.add_argument('--http-01-port', type=int, default=DEFAULT_HTTP_01_PORT,
|
||||
help='specify the port to use for http-01 validation; '
|
||||
'this is currently only supported for Pebble.')
|
||||
args = parser.parse_args()
|
||||
|
||||
acme_server = ACMEServer(
|
||||
args.server_type, [], http_proxy=False, stdout=True,
|
||||
dns_server=args.dns_server, http_01_port=args.http_01_port,
|
||||
)
|
||||
acme_server = ACMEServer(args.server_type, [], http_proxy=False, stdout=True, dns_server=args.dns_server)
|
||||
|
||||
try:
|
||||
with acme_server as acme_xdist:
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
"""Module to call certbot in test mode"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
import certbot_integration_tests
|
||||
# pylint: disable=wildcard-import,unused-wildcard-import
|
||||
from certbot_integration_tests.utils.constants import *
|
||||
|
||||
|
||||
@@ -36,8 +35,6 @@ def certbot_test(certbot_args, directory_url, http_01_port, tls_alpn_01_port,
|
||||
|
||||
|
||||
def _prepare_environ(workspace):
|
||||
# pylint: disable=missing-function-docstring
|
||||
|
||||
new_environ = os.environ.copy()
|
||||
new_environ['TMPDIR'] = workspace
|
||||
|
||||
@@ -61,13 +58,8 @@ def _prepare_environ(workspace):
|
||||
# certbot_integration_tests.__file__ is:
|
||||
# '/path/to/certbot/certbot-ci/certbot_integration_tests/__init__.pyc'
|
||||
# ... and we want '/path/to/certbot'
|
||||
certbot_root = os.path.dirname(os.path.dirname(
|
||||
os.path.dirname(certbot_integration_tests.__file__))
|
||||
)
|
||||
python_paths = [
|
||||
path for path in new_environ['PYTHONPATH'].split(':')
|
||||
if path != certbot_root
|
||||
]
|
||||
certbot_root = os.path.dirname(os.path.dirname(os.path.dirname(certbot_integration_tests.__file__)))
|
||||
python_paths = [path for path in new_environ['PYTHONPATH'].split(':') if path != certbot_root]
|
||||
new_environ['PYTHONPATH'] = ':'.join(python_paths)
|
||||
|
||||
return new_environ
|
||||
@@ -78,8 +70,7 @@ def _compute_additional_args(workspace, environ, force_renew):
|
||||
output = subprocess.check_output(['certbot', '--version'],
|
||||
universal_newlines=True, stderr=subprocess.STDOUT,
|
||||
cwd=workspace, env=environ)
|
||||
# Typical response is: output = 'certbot 0.31.0.dev0'
|
||||
version_str = output.split(' ')[1].strip()
|
||||
version_str = output.split(' ')[1].strip() # Typical response is: output = 'certbot 0.31.0.dev0'
|
||||
if LooseVersion(version_str) >= LooseVersion('0.30.0'):
|
||||
additional_args.append('--no-random-sleep-on-renew')
|
||||
|
||||
@@ -122,12 +113,11 @@ def _prepare_args_env(certbot_args, directory_url, http_01_port, tls_alpn_01_por
|
||||
|
||||
|
||||
def main():
|
||||
# pylint: disable=missing-function-docstring
|
||||
args = sys.argv[1:]
|
||||
|
||||
# Default config is pebble
|
||||
directory_url = os.environ.get('SERVER', PEBBLE_DIRECTORY_URL)
|
||||
http_01_port = int(os.environ.get('HTTP_01_PORT', DEFAULT_HTTP_01_PORT))
|
||||
http_01_port = int(os.environ.get('HTTP_01_PORT', HTTP_01_PORT))
|
||||
tls_alpn_01_port = int(os.environ.get('TLS_ALPN_01_PORT', TLS_ALPN_01_PORT))
|
||||
|
||||
# Execution of certbot in a self-contained workspace
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""Some useful constants to use throughout certbot-ci integration tests"""
|
||||
DEFAULT_HTTP_01_PORT = 5002
|
||||
HTTP_01_PORT = 5002
|
||||
TLS_ALPN_01_PORT = 5001
|
||||
CHALLTESTSRV_PORT = 8055
|
||||
BOULDER_V1_DIRECTORY_URL = 'http://localhost:4000/directory'
|
||||
@@ -7,4 +7,4 @@ BOULDER_V2_DIRECTORY_URL = 'http://localhost:4001/directory'
|
||||
PEBBLE_DIRECTORY_URL = 'https://localhost:14000/dir'
|
||||
PEBBLE_MANAGEMENT_URL = 'https://localhost:15000'
|
||||
MOCK_OCSP_SERVER_PORT = 4002
|
||||
PEBBLE_ALTERNATE_ROOTS = 2
|
||||
PEBBLE_ALTERNATE_ROOTS = 2
|
||||
@@ -4,6 +4,7 @@ from __future__ import print_function
|
||||
|
||||
import os
|
||||
import os.path
|
||||
from pkg_resources import resource_filename
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
@@ -11,14 +12,13 @@ import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from pkg_resources import resource_filename
|
||||
|
||||
BIND_DOCKER_IMAGE = "internetsystemsconsortium/bind9:9.16"
|
||||
BIND_BIND_ADDRESS = ("127.0.0.1", 45953)
|
||||
BIND_DOCKER_IMAGE = 'internetsystemsconsortium/bind9:9.16'
|
||||
BIND_BIND_ADDRESS = ('127.0.0.1', 45953)
|
||||
|
||||
# A TCP DNS message which is a query for '. CH A' transaction ID 0xcb37. This is used
|
||||
# by _wait_until_ready to check that BIND is responding without depending on dnspython.
|
||||
BIND_TEST_QUERY = bytearray.fromhex("0011cb37000000010000000000000000010003")
|
||||
BIND_TEST_QUERY = bytearray.fromhex('0011cb37000000010000000000000000010003')
|
||||
|
||||
|
||||
class DNSServer(object):
|
||||
@@ -31,7 +31,7 @@ class DNSServer(object):
|
||||
future to support parallelization (https://github.com/certbot/certbot/issues/8455).
|
||||
"""
|
||||
|
||||
def __init__(self, unused_nodes, show_output=False):
|
||||
def __init__(self, nodes, show_output=False):
|
||||
"""
|
||||
Create an DNSServer instance.
|
||||
:param list nodes: list of node names that will be setup by pytest xdist
|
||||
@@ -40,13 +40,16 @@ class DNSServer(object):
|
||||
|
||||
self.bind_root = tempfile.mkdtemp()
|
||||
|
||||
self.process = None # type: subprocess.Popen
|
||||
self.process = None
|
||||
|
||||
self.dns_xdist = {"address": BIND_BIND_ADDRESS[0], "port": BIND_BIND_ADDRESS[1]}
|
||||
self.dns_xdist = {
|
||||
'address': BIND_BIND_ADDRESS[0],
|
||||
'port': BIND_BIND_ADDRESS[1]
|
||||
}
|
||||
|
||||
# Unfortunately the BIND9 image forces everything to stderr with -g and we can't
|
||||
# modify the verbosity.
|
||||
self._output = sys.stderr if show_output else open(os.devnull, "w")
|
||||
self._output = sys.stderr if show_output else open(os.devnull, 'w')
|
||||
|
||||
def start(self):
|
||||
"""Start the DNS server"""
|
||||
@@ -60,11 +63,11 @@ class DNSServer(object):
|
||||
def stop(self):
|
||||
"""Stop the DNS server, and clean its resources"""
|
||||
if self.process:
|
||||
try:
|
||||
self.process.terminate()
|
||||
self.process.wait()
|
||||
except BaseException as e:
|
||||
print("BIND9 did not stop cleanly: {}".format(e), file=sys.stderr)
|
||||
try:
|
||||
self.process.terminate()
|
||||
self.process.wait()
|
||||
except BaseException as e:
|
||||
print("BIND9 did not stop cleanly: {}".format(e), file=sys.stderr)
|
||||
|
||||
shutil.rmtree(self.bind_root, ignore_errors=True)
|
||||
|
||||
@@ -73,79 +76,65 @@ class DNSServer(object):
|
||||
|
||||
def _configure_bind(self):
|
||||
"""Configure the BIND9 server based on the prebaked configuration"""
|
||||
bind_conf_src = resource_filename(
|
||||
"certbot_integration_tests", "assets/bind-config"
|
||||
)
|
||||
for directory in ("conf", "zones"):
|
||||
shutil.copytree(
|
||||
os.path.join(bind_conf_src, directory), os.path.join(self.bind_root, directory)
|
||||
)
|
||||
bind_conf_src = resource_filename('certbot_integration_tests', 'assets/bind-config')
|
||||
for dir in ('conf', 'zones'):
|
||||
shutil.copytree(os.path.join(bind_conf_src, dir), os.path.join(self.bind_root, dir))
|
||||
|
||||
def _start_bind(self):
|
||||
"""Launch the BIND9 server as a Docker container"""
|
||||
addr_str = "{}:{}".format(BIND_BIND_ADDRESS[0], BIND_BIND_ADDRESS[1])
|
||||
self.process = subprocess.Popen(
|
||||
[
|
||||
"docker",
|
||||
"run",
|
||||
"--rm",
|
||||
"-p",
|
||||
"{}:53/udp".format(addr_str),
|
||||
"-p",
|
||||
"{}:53/tcp".format(addr_str),
|
||||
"-v",
|
||||
"{}/conf:/etc/bind".format(self.bind_root),
|
||||
"-v",
|
||||
"{}/zones:/var/lib/bind".format(self.bind_root),
|
||||
BIND_DOCKER_IMAGE,
|
||||
],
|
||||
stdout=self._output,
|
||||
stderr=self._output,
|
||||
)
|
||||
addr_str = '{}:{}'.format(BIND_BIND_ADDRESS[0], BIND_BIND_ADDRESS[1])
|
||||
self.process = subprocess.Popen([
|
||||
'docker', 'run', '--rm',
|
||||
'-p', '{}:53/udp'.format(addr_str),
|
||||
'-p', '{}:53/tcp'.format(addr_str),
|
||||
'-v', '{}/conf:/etc/bind'.format(self.bind_root),
|
||||
'-v', '{}/zones:/var/lib/bind'.format(self.bind_root),
|
||||
BIND_DOCKER_IMAGE
|
||||
], stdout=self._output, stderr=self._output)
|
||||
|
||||
if self.process.poll():
|
||||
raise ValueError("BIND9 server stopped unexpectedly")
|
||||
raise("BIND9 server stopped unexpectedly")
|
||||
|
||||
try:
|
||||
self._wait_until_ready()
|
||||
self._wait_until_ready()
|
||||
except:
|
||||
# The container might be running even if we think it isn't
|
||||
self.stop()
|
||||
raise
|
||||
# The container might be running even if we think it isn't
|
||||
self.stop()
|
||||
raise
|
||||
|
||||
def _wait_until_ready(self, attempts=30):
|
||||
# type: (int) -> None
|
||||
"""
|
||||
Polls the DNS server over TCP until it gets a response, or until
|
||||
it runs out of attempts and raises a ValueError.
|
||||
The DNS response message must match the txn_id of the DNS query message,
|
||||
but otherwise the contents are ignored.
|
||||
:param int attempts: The number of attempts to make.
|
||||
"""
|
||||
for _ in range(attempts):
|
||||
if self.process.poll():
|
||||
raise ValueError("BIND9 server stopped unexpectedly")
|
||||
# type: (int) -> None
|
||||
"""
|
||||
Polls the DNS server over TCP until it gets a response, or until
|
||||
it runs out of attempts and raises a ValueError.
|
||||
The DNS response message must match the txn_id of the DNS query message,
|
||||
but otherwise the contents are ignored.
|
||||
:param int attempts: The number of attempts to make.
|
||||
"""
|
||||
for _ in range(attempts):
|
||||
if self.process.poll():
|
||||
raise ValueError('BIND9 server stopped unexpectedly')
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(5.0)
|
||||
try:
|
||||
sock.connect(BIND_BIND_ADDRESS)
|
||||
sock.sendall(BIND_TEST_QUERY)
|
||||
buf = sock.recv(1024)
|
||||
# We should receive a DNS message with the same tx_id
|
||||
if buf and len(buf) > 4 and buf[2:4] == BIND_TEST_QUERY[2:4]:
|
||||
return
|
||||
# If we got a response but it wasn't the one we wanted, wait a little
|
||||
time.sleep(1)
|
||||
except: # pylint: disable=bare-except
|
||||
# If there was a network error, wait a little
|
||||
time.sleep(1)
|
||||
finally:
|
||||
sock.close()
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(5.0)
|
||||
try:
|
||||
sock.connect(BIND_BIND_ADDRESS)
|
||||
sock.sendall(BIND_TEST_QUERY)
|
||||
buf = sock.recv(1024)
|
||||
# We should receive a DNS message with the same tx_id
|
||||
if buf and len(buf) > 4 and buf[2:4] == BIND_TEST_QUERY[2:4]:
|
||||
return
|
||||
# If we got a response but it wasn't the one we wanted, wait a little
|
||||
time.sleep(1)
|
||||
except:
|
||||
# If there was a network error, wait a little
|
||||
time.sleep(1)
|
||||
pass
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
raise ValueError(
|
||||
"Gave up waiting for DNS server {} to respond".format(BIND_BIND_ADDRESS)
|
||||
)
|
||||
raise ValueError(
|
||||
'Gave up waiting for DNS server {} to respond'.format(BIND_BIND_ADDRESS))
|
||||
|
||||
def __enter__(self):
|
||||
self.start()
|
||||
|
||||
@@ -39,7 +39,6 @@ def _suppress_x509_verification_warnings():
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
except ImportError:
|
||||
# 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)
|
||||
|
||||
@@ -257,8 +256,7 @@ def generate_csr(domains, key_path, csr_path, key_type=RSA_KEY_TYPE):
|
||||
|
||||
def read_certificate(cert_path):
|
||||
"""
|
||||
Load the certificate from the provided path, and return a human readable version
|
||||
of it (TEXT mode).
|
||||
Load the certificate from the provided path, and return a human readable version of it (TEXT mode).
|
||||
:param str cert_path: the path to the certificate
|
||||
:returns: the TEXT version of the certificate, as it would be displayed by openssl binary
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
import json
|
||||
import os
|
||||
import stat
|
||||
@@ -7,19 +5,18 @@ import stat
|
||||
import pkg_resources
|
||||
import requests
|
||||
|
||||
from certbot_integration_tests.utils.constants import DEFAULT_HTTP_01_PORT, MOCK_OCSP_SERVER_PORT
|
||||
from certbot_integration_tests.utils.constants import MOCK_OCSP_SERVER_PORT
|
||||
|
||||
PEBBLE_VERSION = 'v2.3.0'
|
||||
ASSETS_PATH = pkg_resources.resource_filename('certbot_integration_tests', 'assets')
|
||||
|
||||
|
||||
def fetch(workspace, http_01_port=DEFAULT_HTTP_01_PORT):
|
||||
# pylint: disable=missing-function-docstring
|
||||
def fetch(workspace):
|
||||
suffix = 'linux-amd64' if os.name != 'nt' else 'windows-amd64.exe'
|
||||
|
||||
pebble_path = _fetch_asset('pebble', suffix)
|
||||
challtestsrv_path = _fetch_asset('pebble-challtestsrv', suffix)
|
||||
pebble_config_path = _build_pebble_config(workspace, http_01_port)
|
||||
pebble_config_path = _build_pebble_config(workspace)
|
||||
|
||||
return pebble_path, challtestsrv_path, pebble_config_path
|
||||
|
||||
@@ -38,7 +35,7 @@ def _fetch_asset(asset, suffix):
|
||||
return asset_path
|
||||
|
||||
|
||||
def _build_pebble_config(workspace, http_01_port):
|
||||
def _build_pebble_config(workspace):
|
||||
config_path = os.path.join(workspace, 'pebble-config.json')
|
||||
with open(config_path, 'w') as file_h:
|
||||
file_h.write(json.dumps({
|
||||
@@ -47,7 +44,7 @@ def _build_pebble_config(workspace, http_01_port):
|
||||
'managementListenAddress': '0.0.0.0:15000',
|
||||
'certificate': os.path.join(ASSETS_PATH, 'cert.pem'),
|
||||
'privateKey': os.path.join(ASSETS_PATH, 'key.pem'),
|
||||
'httpPort': http_01_port,
|
||||
'httpPort': 5002,
|
||||
'tlsPort': 5001,
|
||||
'ocspResponderURL': 'http://127.0.0.1:{0}'.format(MOCK_OCSP_SERVER_PORT),
|
||||
},
|
||||
|
||||
@@ -21,7 +21,6 @@ from certbot_integration_tests.utils.misc import GracefulTCPServer
|
||||
|
||||
|
||||
class _ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
# pylint: disable=missing-function-docstring
|
||||
def do_POST(self):
|
||||
request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediate-keys/0', verify=False)
|
||||
issuer_key = serialization.load_pem_private_key(request.content, None, default_backend())
|
||||
@@ -36,28 +35,20 @@ class _ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
||||
ocsp_request = ocsp.load_der_ocsp_request(self.rfile.read(content_len))
|
||||
response = requests.get('{0}/cert-status-by-serial/{1}'.format(
|
||||
PEBBLE_MANAGEMENT_URL, str(hex(ocsp_request.serial_number)).replace('0x', '')),
|
||||
verify=False
|
||||
)
|
||||
PEBBLE_MANAGEMENT_URL, str(hex(ocsp_request.serial_number)).replace('0x', '')), verify=False)
|
||||
|
||||
if not response.ok:
|
||||
ocsp_response = ocsp.OCSPResponseBuilder.build_unsuccessful(
|
||||
ocsp.OCSPResponseStatus.UNAUTHORIZED
|
||||
)
|
||||
ocsp_response = ocsp.OCSPResponseBuilder.build_unsuccessful(ocsp.OCSPResponseStatus.UNAUTHORIZED)
|
||||
else:
|
||||
data = response.json()
|
||||
|
||||
now = datetime.datetime.utcnow()
|
||||
cert = x509.load_pem_x509_certificate(data['Certificate'].encode(), default_backend())
|
||||
if data['Status'] != 'Revoked':
|
||||
ocsp_status = ocsp.OCSPCertStatus.GOOD
|
||||
revocation_time = None
|
||||
revocation_reason = None
|
||||
ocsp_status, revocation_time, revocation_reason = ocsp.OCSPCertStatus.GOOD, None, None
|
||||
else:
|
||||
ocsp_status = ocsp.OCSPCertStatus.REVOKED
|
||||
revocation_reason = x509.ReasonFlags.unspecified
|
||||
# "... +0000 UTC" => "+0000"
|
||||
revoked_at = re.sub(r'( \+\d{4}).*$', r'\1', data['RevokedAt'])
|
||||
ocsp_status, revocation_reason = ocsp.OCSPCertStatus.REVOKED, x509.ReasonFlags.unspecified
|
||||
revoked_at = re.sub(r'( \+\d{4}).*$', r'\1', data['RevokedAt']) # "... +0000 UTC" => "+0000"
|
||||
revocation_time = parser.parse(revoked_at)
|
||||
|
||||
ocsp_response = ocsp.OCSPResponseBuilder().add_response(
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=missing-module-docstring
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
@@ -12,9 +10,7 @@ from certbot_integration_tests.utils.misc import GracefulTCPServer
|
||||
|
||||
|
||||
def _create_proxy(mapping):
|
||||
# pylint: disable=missing-function-docstring
|
||||
class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
# pylint: disable=missing-class-docstring
|
||||
def do_GET(self):
|
||||
headers = {key.lower(): value for key, value in self.headers.items()}
|
||||
backend = [backend for pattern, backend in mapping.items()
|
||||
|
||||
@@ -18,7 +18,7 @@ install_requires = [
|
||||
'python-dateutil',
|
||||
'pyyaml',
|
||||
'requests',
|
||||
'six'
|
||||
'six',
|
||||
]
|
||||
|
||||
# Add pywin32 on Windows platforms to handle low-level system calls.
|
||||
@@ -40,12 +40,14 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'certbot',
|
||||
@@ -38,12 +38,14 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_cloudflare.dns_cloudflare` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the Cloudflare API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,13 +6,13 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'cloudflare>=1.5.1',
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -49,7 +49,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -57,6 +57,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_cloudxns.dns_cloudxns` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the CloudXNS API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,13 +6,13 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -49,7 +49,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -57,6 +57,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_digitalocean.dns_digitalocean` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the DigitalOcean API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -19,8 +19,7 @@ class Authenticator(dns_common.DNSAuthenticator):
|
||||
This Authenticator uses the DigitalOcean API to fulfill a dns-01 challenge.
|
||||
"""
|
||||
|
||||
description = 'Obtain certificates using a DNS TXT record (if you are ' + \
|
||||
'using DigitalOcean for DNS).'
|
||||
description = 'Obtain certs using a DNS TXT record (if you are using DigitalOcean for DNS).'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Authenticator, self).__init__(*args, **kwargs)
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,14 +6,14 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'python-digitalocean>=1.11',
|
||||
'setuptools>=39.0.1',
|
||||
'six>=1.11.0',
|
||||
'setuptools',
|
||||
'six',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -50,7 +50,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -58,6 +58,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_dnsimple.dns_dnsimple` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the DNSimple API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,12 +6,12 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -60,7 +60,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -68,6 +68,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_dnsmadeeasy.dns_dnsmadeeasy` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the DNS Made Easy API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,13 +6,13 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -49,7 +49,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -57,6 +57,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_gehirn.dns_gehirn` plugin automates the process of completing
|
||||
a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and subsequently
|
||||
removing, TXT records using the Gehirn Infrastructure Service DNS API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,12 +6,12 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'dns-lexicon>=2.1.22',
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -48,7 +48,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -56,6 +56,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_google.dns_google` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the Google Cloud DNS API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -118,13 +118,10 @@ class _GoogleClient(object):
|
||||
|
||||
record_contents = self.get_existing_txt_rrset(zone_id, record_name)
|
||||
if record_contents is None:
|
||||
# If it wasn't possible to fetch the records at this label (missing .list permission),
|
||||
# assume there aren't any (#5678). If there are actually records here, this will fail
|
||||
# with HTTP 409/412 API errors.
|
||||
record_contents = {"rrdatas": []}
|
||||
add_records = record_contents["rrdatas"][:]
|
||||
record_contents = []
|
||||
add_records = record_contents[:]
|
||||
|
||||
if "\""+record_content+"\"" in record_contents["rrdatas"]:
|
||||
if "\""+record_content+"\"" in record_contents:
|
||||
# The process was interrupted previously and validation token exists
|
||||
return
|
||||
|
||||
@@ -143,15 +140,15 @@ class _GoogleClient(object):
|
||||
],
|
||||
}
|
||||
|
||||
if record_contents["rrdatas"]:
|
||||
if record_contents:
|
||||
# We need to remove old records in the same request
|
||||
data["deletions"] = [
|
||||
{
|
||||
"kind": "dns#resourceRecordSet",
|
||||
"type": "TXT",
|
||||
"name": record_name + ".",
|
||||
"rrdatas": record_contents["rrdatas"],
|
||||
"ttl": record_contents["ttl"],
|
||||
"rrdatas": record_contents,
|
||||
"ttl": record_ttl,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -191,10 +188,7 @@ class _GoogleClient(object):
|
||||
|
||||
record_contents = self.get_existing_txt_rrset(zone_id, record_name)
|
||||
if record_contents is None:
|
||||
# If it wasn't possible to fetch the records at this label (missing .list permission),
|
||||
# assume there aren't any (#5678). If there are actually records here, this will fail
|
||||
# with HTTP 409/412 API errors.
|
||||
record_contents = {"rrdatas": ["\"" + record_content + "\""], "ttl": record_ttl}
|
||||
record_contents = ["\"" + record_content + "\""]
|
||||
|
||||
data = {
|
||||
"kind": "dns#change",
|
||||
@@ -203,15 +197,14 @@ class _GoogleClient(object):
|
||||
"kind": "dns#resourceRecordSet",
|
||||
"type": "TXT",
|
||||
"name": record_name + ".",
|
||||
"rrdatas": record_contents["rrdatas"],
|
||||
"ttl": record_contents["ttl"],
|
||||
"rrdatas": record_contents,
|
||||
"ttl": record_ttl,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
# Remove the record being deleted from the list
|
||||
readd_contents = [r for r in record_contents["rrdatas"]
|
||||
if r != "\"" + record_content + "\""]
|
||||
readd_contents = [r for r in record_contents if r != "\"" + record_content + "\""]
|
||||
if readd_contents:
|
||||
# We need to remove old records in the same request
|
||||
data["additions"] = [
|
||||
@@ -220,7 +213,7 @@ class _GoogleClient(object):
|
||||
"type": "TXT",
|
||||
"name": record_name + ".",
|
||||
"rrdatas": readd_contents,
|
||||
"ttl": record_contents["ttl"],
|
||||
"ttl": record_ttl,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -242,15 +235,14 @@ class _GoogleClient(object):
|
||||
:param str zone_id: The ID of the managed zone.
|
||||
:param str record_name: The record name (typically beginning with '_acme-challenge.').
|
||||
|
||||
:returns: The resourceRecordSet corresponding to `record_name` or None
|
||||
:rtype: `resourceRecordSet <https://cloud.google.com/dns/docs/reference/v1/resourceRecordSets#resource>` or `None` # pylint: disable=line-too-long
|
||||
:returns: List of TXT record values or None
|
||||
:rtype: `list` of `string` or `None`
|
||||
|
||||
"""
|
||||
rrs_request = self.dns.resourceRecordSets()
|
||||
request = rrs_request.list(managedZone=zone_id, project=self.project_id)
|
||||
# Add dot as the API returns absolute domains
|
||||
record_name += "."
|
||||
request = rrs_request.list(project=self.project_id, managedZone=zone_id, name=record_name,
|
||||
type="TXT")
|
||||
try:
|
||||
response = request.execute()
|
||||
except googleapiclient_errors.Error:
|
||||
@@ -258,8 +250,10 @@ class _GoogleClient(object):
|
||||
"requesting a wildcard certificate, this might not work.")
|
||||
logger.debug("Error was:", exc_info=True)
|
||||
else:
|
||||
if response and response["rrsets"]:
|
||||
return response["rrsets"][0]
|
||||
if response:
|
||||
for rr in response["rrsets"]:
|
||||
if rr["name"] == record_name and rr["type"] == "TXT":
|
||||
return rr["rrdatas"]
|
||||
return None
|
||||
|
||||
def _find_managed_zone_id(self, domain):
|
||||
|
||||
@@ -112,7 +112,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,14 +6,14 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'google-api-python-client>=1.5.5',
|
||||
'oauth2client>=4.0',
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
# already a dependency of google-api-python-client, but added for consistency
|
||||
'httplib2'
|
||||
@@ -52,7 +52,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -60,6 +60,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -70,7 +70,7 @@ class GoogleClientTest(unittest.TestCase):
|
||||
zone = "ZONE_ID"
|
||||
change = "an-id"
|
||||
|
||||
def _setUp_client_with_mock(self, zone_request_side_effect, rrs_list_side_effect=None):
|
||||
def _setUp_client_with_mock(self, zone_request_side_effect):
|
||||
from certbot_dns_google._internal.dns_google import _GoogleClient
|
||||
|
||||
pwd = os.path.dirname(__file__)
|
||||
@@ -86,16 +86,9 @@ class GoogleClientTest(unittest.TestCase):
|
||||
mock_mz.list.return_value.execute.side_effect = zone_request_side_effect
|
||||
|
||||
mock_rrs = mock.MagicMock()
|
||||
def rrs_list(project=None, managedZone=None, name=None, type=None):
|
||||
response = {"rrsets": []}
|
||||
if name == "_acme-challenge.example.org.":
|
||||
response = {"rrsets": [{"name": "_acme-challenge.example.org.", "type": "TXT",
|
||||
"rrdatas": ["\"example-txt-contents\""], "ttl": 60}]}
|
||||
mock_return = mock.MagicMock()
|
||||
mock_return.execute.return_value = response
|
||||
mock_return.execute.side_effect = rrs_list_side_effect
|
||||
return mock_return
|
||||
mock_rrs.list.side_effect = rrs_list
|
||||
rrsets = {"rrsets": [{"name": "_acme-challenge.example.org.", "type": "TXT",
|
||||
"rrdatas": ["\"example-txt-contents\""]}]}
|
||||
mock_rrs.list.return_value.execute.return_value = rrsets
|
||||
mock_changes = mock.MagicMock()
|
||||
|
||||
client.dns.managedZones = mock.MagicMock(return_value=mock_mz)
|
||||
@@ -180,29 +173,11 @@ class GoogleClientTest(unittest.TestCase):
|
||||
# pylint: disable=line-too-long
|
||||
mock_get_rrs = "certbot_dns_google._internal.dns_google._GoogleClient.get_existing_txt_rrset"
|
||||
with mock.patch(mock_get_rrs) as mock_rrs:
|
||||
mock_rrs.return_value = {"rrdatas": ["sample-txt-contents"], "ttl": self.record_ttl}
|
||||
mock_rrs.return_value = ["sample-txt-contents"]
|
||||
client.add_txt_record(DOMAIN, self.record_name, self.record_content, self.record_ttl)
|
||||
self.assertTrue(changes.create.called)
|
||||
deletions = changes.create.call_args_list[0][1]["body"]["deletions"][0]
|
||||
self.assertTrue("sample-txt-contents" in deletions["rrdatas"])
|
||||
self.assertEqual(self.record_ttl, deletions["ttl"])
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_add_txt_record_delete_old_ttl_case(self, unused_credential_mock):
|
||||
client, changes = self._setUp_client_with_mock(
|
||||
[{'managedZones': [{'id': self.zone}]}])
|
||||
# pylint: disable=line-too-long
|
||||
mock_get_rrs = "certbot_dns_google._internal.dns_google._GoogleClient.get_existing_txt_rrset"
|
||||
with mock.patch(mock_get_rrs) as mock_rrs:
|
||||
custom_ttl = 300
|
||||
mock_rrs.return_value = {"rrdatas": ["sample-txt-contents"], "ttl": custom_ttl}
|
||||
client.add_txt_record(DOMAIN, self.record_name, self.record_content, self.record_ttl)
|
||||
self.assertTrue(changes.create.called)
|
||||
deletions = changes.create.call_args_list[0][1]["body"]["deletions"][0]
|
||||
self.assertTrue("sample-txt-contents" in deletions["rrdatas"])
|
||||
self.assertEqual(custom_ttl, deletions["ttl"]) #otherwise HTTP 412
|
||||
self.assertTrue("sample-txt-contents" in
|
||||
changes.create.call_args_list[0][1]["body"]["deletions"][0]["rrdatas"])
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
@@ -246,13 +221,14 @@ class GoogleClientTest(unittest.TestCase):
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_del_txt_record_multi_rrdatas(self, unused_credential_mock):
|
||||
def test_del_txt_record(self, unused_credential_mock):
|
||||
client, changes = self._setUp_client_with_mock([{'managedZones': [{'id': self.zone}]}])
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
mock_get_rrs = "certbot_dns_google._internal.dns_google._GoogleClient.get_existing_txt_rrset"
|
||||
with mock.patch(mock_get_rrs) as mock_rrs:
|
||||
mock_rrs.return_value = {"rrdatas": ["\"sample-txt-contents\"",
|
||||
"\"example-txt-contents\""], "ttl": self.record_ttl}
|
||||
mock_rrs.return_value = ["\"sample-txt-contents\"",
|
||||
"\"example-txt-contents\""]
|
||||
client.del_txt_record(DOMAIN, "_acme-challenge.example.org",
|
||||
"example-txt-contents", self.record_ttl)
|
||||
|
||||
@@ -282,51 +258,22 @@ class GoogleClientTest(unittest.TestCase):
|
||||
managedZone=self.zone,
|
||||
project=PROJECT_ID)
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_del_txt_record_single_rrdatas(self, unused_credential_mock):
|
||||
client, changes = self._setUp_client_with_mock([{'managedZones': [{'id': self.zone}]}])
|
||||
# pylint: disable=line-too-long
|
||||
mock_get_rrs = "certbot_dns_google._internal.dns_google._GoogleClient.get_existing_txt_rrset"
|
||||
with mock.patch(mock_get_rrs) as mock_rrs:
|
||||
mock_rrs.return_value = {"rrdatas": ["\"example-txt-contents\""], "ttl": self.record_ttl}
|
||||
client.del_txt_record(DOMAIN, "_acme-challenge.example.org",
|
||||
"example-txt-contents", self.record_ttl)
|
||||
|
||||
expected_body = {
|
||||
"kind": "dns#change",
|
||||
"deletions": [
|
||||
{
|
||||
"kind": "dns#resourceRecordSet",
|
||||
"type": "TXT",
|
||||
"name": "_acme-challenge.example.org.",
|
||||
"rrdatas": ["\"example-txt-contents\""],
|
||||
"ttl": self.record_ttl,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
changes.create.assert_called_with(body=expected_body,
|
||||
managedZone=self.zone,
|
||||
project=PROJECT_ID)
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_del_txt_record_error_during_zone_lookup(self, unused_credential_mock):
|
||||
client, changes = self._setUp_client_with_mock(API_ERROR)
|
||||
client, unused_changes = self._setUp_client_with_mock(API_ERROR)
|
||||
|
||||
client.del_txt_record(DOMAIN, self.record_name, self.record_content, self.record_ttl)
|
||||
changes.create.assert_not_called()
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_del_txt_record_zone_not_found(self, unused_credential_mock):
|
||||
client, changes = self._setUp_client_with_mock([{'managedZones': []},
|
||||
client, unused_changes = self._setUp_client_with_mock([{'managedZones': []},
|
||||
{'managedZones': []}])
|
||||
|
||||
client.del_txt_record(DOMAIN, self.record_name, self.record_content, self.record_ttl)
|
||||
changes.create.assert_not_called()
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
@@ -340,39 +287,24 @@ class GoogleClientTest(unittest.TestCase):
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_get_existing_found(self, unused_credential_mock):
|
||||
def test_get_existing(self, unused_credential_mock):
|
||||
client, unused_changes = self._setUp_client_with_mock(
|
||||
[{'managedZones': [{'id': self.zone}]}])
|
||||
# Record name mocked in setUp
|
||||
found = client.get_existing_txt_rrset(self.zone, "_acme-challenge.example.org")
|
||||
self.assertEqual(found["rrdatas"], ["\"example-txt-contents\""])
|
||||
self.assertEqual(found["ttl"], 60)
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_get_existing_not_found(self, unused_credential_mock):
|
||||
client, unused_changes = self._setUp_client_with_mock(
|
||||
[{'managedZones': [{'id': self.zone}]}])
|
||||
self.assertEqual(found, ["\"example-txt-contents\""])
|
||||
not_found = client.get_existing_txt_rrset(self.zone, "nonexistent.tld")
|
||||
self.assertEqual(not_found, None)
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_get_existing_with_error(self, unused_credential_mock):
|
||||
client, unused_changes = self._setUp_client_with_mock(
|
||||
[{'managedZones': [{'id': self.zone}]}], API_ERROR)
|
||||
# Record name mocked in setUp
|
||||
found = client.get_existing_txt_rrset(self.zone, "_acme-challenge.example.org")
|
||||
self.assertEqual(found, None)
|
||||
|
||||
@mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name')
|
||||
@mock.patch('certbot_dns_google._internal.dns_google.open',
|
||||
mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True)
|
||||
def test_get_existing_fallback(self, unused_credential_mock):
|
||||
client, unused_changes = self._setUp_client_with_mock(
|
||||
[{'managedZones': [{'id': self.zone}]}], API_ERROR)
|
||||
[{'managedZones': [{'id': self.zone}]}])
|
||||
mock_execute = client.dns.resourceRecordSets.return_value.list.return_value.execute
|
||||
mock_execute.side_effect = API_ERROR
|
||||
|
||||
rrset = client.get_existing_txt_rrset(self.zone, "_acme-challenge.example.org")
|
||||
self.assertFalse(rrset)
|
||||
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_linode.dns_linode` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the Linode API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -24,7 +24,7 @@ class Authenticator(dns_common.DNSAuthenticator):
|
||||
This Authenticator uses the Linode API to fulfill a dns-01 challenge.
|
||||
"""
|
||||
|
||||
description = 'Obtain certificates using a DNS TXT record (if you are using Linode for DNS).'
|
||||
description = 'Obtain certs using a DNS TXT record (if you are using Linode for DNS).'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Authenticator, self).__init__(*args, **kwargs)
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,12 +6,12 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'dns-lexicon>=2.2.3',
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -48,7 +48,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -56,6 +56,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_luadns.dns_luadns` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the LuaDNS API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,13 +6,13 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -49,7 +49,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -57,6 +57,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_nsone.dns_nsone` plugin automates the process of completing
|
||||
a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and subsequently
|
||||
removing, TXT records using the NS1 API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,13 +6,13 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -49,7 +49,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -57,6 +57,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_ovh.dns_ovh` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the OVH API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,13 +6,13 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -49,7 +49,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -57,6 +57,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_rfc2136.dns_rfc2136` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using RFC 2136 Dynamic Updates.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
# type: ignore
|
||||
# pylint: disable=no-member
|
||||
# Many attributes of dnspython are now dynamically defined which causes both
|
||||
# mypy and pylint to error about accessing attributes they think do not exist.
|
||||
# This is the case even in up-to-date versions of mypy and pylint which as of
|
||||
# writing this are 0.790 and 2.6.0 respectively. This problem may be fixed in
|
||||
# dnspython 2.1.0. See https://github.com/rthalley/dnspython/issues/598. For
|
||||
# now, let's disable these checks. This is done at the very top of the file
|
||||
# like this because "type: ignore" must be the first line in the file to be
|
||||
# respected by mypy.
|
||||
"""DNS Authenticator using RFC 2136 Dynamic Updates."""
|
||||
import logging
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,13 +6,13 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'dnspython',
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -49,7 +49,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -57,6 +57,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
include LICENSE.txt
|
||||
include README.rst
|
||||
include README
|
||||
recursive-include docs *
|
||||
recursive-include tests *
|
||||
global-exclude __pycache__
|
||||
|
||||
35
certbot-dns-route53/README.md
Normal file
35
certbot-dns-route53/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
## Route53 plugin for Let's Encrypt client
|
||||
|
||||
### Before you start
|
||||
|
||||
It's expected that the root hosted zone for the domain in question already
|
||||
exists in your account.
|
||||
|
||||
### Setup
|
||||
|
||||
1. Create a virtual environment
|
||||
|
||||
2. Update its pip and setuptools (`VENV/bin/pip install -U setuptools pip`)
|
||||
to avoid problems with cryptography's dependency on setuptools>=11.3.
|
||||
|
||||
3. Make sure you have libssl-dev and libffi (or your regional equivalents)
|
||||
installed. You might have to set compiler flags to pick things up (I have to
|
||||
use `CPPFLAGS=-I/usr/local/opt/openssl/include
|
||||
LDFLAGS=-L/usr/local/opt/openssl/lib` on my macOS to pick up brew's openssl,
|
||||
for example).
|
||||
|
||||
4. Install this package.
|
||||
|
||||
### How to use it
|
||||
|
||||
Make sure you have access to AWS's Route53 service, either through IAM roles or
|
||||
via `.aws/credentials`. Check out
|
||||
[sample-aws-policy.json](examples/sample-aws-policy.json) for the necessary permissions.
|
||||
|
||||
To generate a certificate:
|
||||
```
|
||||
certbot certonly \
|
||||
-n --agree-tos --email DEVOPS@COMPANY.COM \
|
||||
--dns-route53 \
|
||||
-d MY.DOMAIN.NAME
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
Amazon Web Services Route 53 DNS Authenticator plugin for Certbot
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_route53.dns_route53` plugin automates the process of
|
||||
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
|
||||
subsequently removing, TXT records using the Amazon Web Services Route 53 API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,13 +6,13 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'boto3',
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -36,11 +36,6 @@ elif 'bdist_wheel' in sys.argv[1:]:
|
||||
elif sys.version_info < (3,3):
|
||||
install_requires.append('mock')
|
||||
|
||||
docs_extras = [
|
||||
'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags
|
||||
'sphinx_rtd_theme',
|
||||
]
|
||||
|
||||
setup(
|
||||
name='certbot-dns-route53',
|
||||
version=version,
|
||||
@@ -49,7 +44,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -57,6 +52,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
@@ -73,9 +70,6 @@ setup(
|
||||
include_package_data=True,
|
||||
install_requires=install_requires,
|
||||
keywords=['certbot', 'route53', 'aws'],
|
||||
extras_require={
|
||||
'docs': docs_extras,
|
||||
},
|
||||
entry_points={
|
||||
'certbot.plugins': [
|
||||
'dns-route53 = certbot_dns_route53._internal.dns_route53:Authenticator',
|
||||
|
||||
@@ -3,10 +3,6 @@ The `~certbot_dns_sakuracloud.dns_sakuracloud` plugin automates the process of c
|
||||
a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and subsequently
|
||||
removing, TXT records using the Sakura Cloud DNS API.
|
||||
|
||||
.. note::
|
||||
The plugin is not installed by default. It can be installed by heading to
|
||||
`certbot.eff.org <https://certbot.eff.org/instructions#wildcard>`_, choosing your system and
|
||||
selecting the Wildcard tab.
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -111,7 +111,7 @@ if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -6,12 +6,12 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'dns-lexicon>=2.1.23',
|
||||
'setuptools>=39.0.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -48,7 +48,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -56,6 +56,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -226,7 +226,7 @@ class NginxConfigurator(common.Installer):
|
||||
if not fullchain_path:
|
||||
raise errors.PluginError(
|
||||
"The nginx plugin currently requires --fullchain-path to "
|
||||
"install a certificate.")
|
||||
"install a cert.")
|
||||
|
||||
vhosts = self.choose_vhosts(domain, create_if_no_match=True)
|
||||
for vhost in vhosts:
|
||||
|
||||
@@ -5,16 +5,16 @@ from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.12.0.dev0'
|
||||
version = '1.11.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=1.4.0',
|
||||
'certbot>=1.6.0',
|
||||
'PyOpenSSL>=17.3.0',
|
||||
'pyparsing>=2.2.0',
|
||||
'setuptools>=39.0.1',
|
||||
'PyOpenSSL',
|
||||
'pyparsing>=1.5.5', # Python3 support
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
@@ -35,7 +35,7 @@ setup(
|
||||
author="Certbot Project",
|
||||
author_email='client-dev@letsencrypt.org',
|
||||
license='Apache License 2.0',
|
||||
python_requires='>=3.6',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Plugins',
|
||||
@@ -43,6 +43,8 @@ setup(
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
|
||||
@@ -2,28 +2,7 @@
|
||||
|
||||
Certbot adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## 1.12.0 - master
|
||||
|
||||
### Added
|
||||
|
||||
*
|
||||
|
||||
### Changed
|
||||
|
||||
* The `--preferred-chain` flag now only checks the Issuer Common Name of the
|
||||
topmost (closest to the root) certificate in the chain, instead of checking
|
||||
every certificate in the chain.
|
||||
See [#8577](https://github.com/certbot/certbot/issues/8577).
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed the apache component on openSUSE Tumbleweed which no longer provides
|
||||
an apache2ctl symlink and uses apachectl instead.
|
||||
* Fixed a typo in `certbot/crypto_util.py` causing an error upon attempting `secp521r1` key generation
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 1.11.0 - 2021-01-05
|
||||
## 1.11.0 - master
|
||||
|
||||
### Added
|
||||
|
||||
@@ -33,9 +12,7 @@ More details about these changes can be found on our GitHub repo.
|
||||
|
||||
* We deprecated support for Python 2 in Certbot and its ACME library.
|
||||
Support for Python 2 will be removed in the next planned release of Certbot.
|
||||
* certbot-auto was deprecated on all systems. For more information about this
|
||||
change, see
|
||||
https://community.letsencrypt.org/t/certbot-auto-no-longer-works-on-debian-based-systems/139702/7.
|
||||
* certbot-auto was deprecated on all systems.
|
||||
* We deprecated support for Apache 2.2 in the certbot-apache plugin and it will
|
||||
be removed in a future release of Certbot.
|
||||
|
||||
@@ -43,8 +20,6 @@ More details about these changes can be found on our GitHub repo.
|
||||
|
||||
* The Certbot snap no longer loads packages installed via `pip install --user`. This
|
||||
was unintended and DNS plugins should be installed via `snap` instead.
|
||||
* `certbot-dns-google` would sometimes crash with HTTP 409/412 errors when used with very large zones. See [#6036](https://github.com/certbot/certbot/issues/6036).
|
||||
* `certbot-dns-google` would sometimes crash with an HTTP 412 error if preexisting records had an unexpected TTL, i.e.: different than Certbot's default TTL for this plugin. See [#8551](https://github.com/certbot/certbot/issues/8551).
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ systems.
|
||||
To see the changes made to Certbot between versions please refer to our
|
||||
`changelog <https://github.com/certbot/certbot/blob/master/certbot/CHANGELOG.md>`_.
|
||||
|
||||
Until May 2016, Certbot was named simply ``letsencrypt`` or ``letsencrypt-auto``,
|
||||
depending on install method. Instructions on the Internet, and some pieces of the
|
||||
software, may still refer to this older name.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
@@ -92,7 +96,7 @@ Current Features
|
||||
- apache/2.x
|
||||
- nginx/0.8.48+
|
||||
- webroot (adds files to webroot directories in order to prove control of
|
||||
domains and obtain certificates)
|
||||
domains and obtain certs)
|
||||
- standalone (runs its own simple webserver to prove you control a domain)
|
||||
- other server software via `third party plugins <https://certbot.eff.org/docs/using.html#third-party-plugins>`_
|
||||
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
"""Certbot client."""
|
||||
import warnings
|
||||
import sys
|
||||
|
||||
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
|
||||
__version__ = '1.12.0.dev0'
|
||||
__version__ = '1.11.0.dev0'
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
warnings.warn(
|
||||
"Python 2 support will be dropped in the next release of Certbot. "
|
||||
"Please upgrade your Python version.",
|
||||
PendingDeprecationWarning,
|
||||
) # pragma: no cover
|
||||
|
||||
@@ -20,7 +20,6 @@ from certbot import interfaces
|
||||
from certbot import util
|
||||
from certbot._internal import constants
|
||||
from certbot.compat import os
|
||||
from certbot.compat import filesystem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -325,7 +324,7 @@ class AccountFileStorage(interfaces.AccountStorage):
|
||||
if server_path in reused_servers:
|
||||
next_server_path = reused_servers[server_path]
|
||||
next_dir_path = link_func(next_server_path)
|
||||
if os.path.islink(next_dir_path) and filesystem.readlink(next_dir_path) == dir_path:
|
||||
if os.path.islink(next_dir_path) and os.readlink(next_dir_path) == dir_path:
|
||||
possible_next_link = True
|
||||
server_path = next_server_path
|
||||
dir_path = next_dir_path
|
||||
@@ -333,7 +332,7 @@ class AccountFileStorage(interfaces.AccountStorage):
|
||||
# if there's not a next one up to delete, then delete me
|
||||
# and whatever I link to
|
||||
while os.path.islink(dir_path):
|
||||
target = filesystem.readlink(dir_path)
|
||||
target = os.readlink(dir_path)
|
||||
os.unlink(dir_path)
|
||||
dir_path = target
|
||||
|
||||
|
||||
@@ -369,7 +369,7 @@ def _describe_certs(config, parsed_certs, parse_failures):
|
||||
notify = out.append
|
||||
|
||||
if not parsed_certs and not parse_failures:
|
||||
notify("No certificates found.")
|
||||
notify("No certs found.")
|
||||
else:
|
||||
if parsed_certs:
|
||||
match = "matching " if config.certname or config.domains else ""
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import print_function
|
||||
import functools
|
||||
import logging.handlers
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
import configobj
|
||||
import josepy as jose
|
||||
@@ -253,7 +254,7 @@ def _handle_identical_cert_request(config, # type: configuration.NamespaceConfi
|
||||
elif config.verb == "certonly":
|
||||
keep_opt = "Keep the existing certificate for now"
|
||||
choices = [keep_opt,
|
||||
"Renew & replace the certificate (may be subject to CA rate limits)"]
|
||||
"Renew & replace the cert (may be subject to CA rate limits)"]
|
||||
|
||||
display = zope.component.getUtility(interfaces.IDisplay)
|
||||
response = display.menu(question, choices,
|
||||
@@ -433,8 +434,8 @@ def _ask_user_to_confirm_new_names(config, new_domains, certname, old_domains):
|
||||
_format_list("-", removed),
|
||||
br=os.linesep))
|
||||
obj = zope.component.getUtility(interfaces.IDisplay)
|
||||
if not obj.yesno(msg, "Update certificate", "Cancel", default=True):
|
||||
raise errors.ConfigurationError("Specified mismatched certificate name and domains.")
|
||||
if not obj.yesno(msg, "Update cert", "Cancel", default=True):
|
||||
raise errors.ConfigurationError("Specified mismatched cert name and domains.")
|
||||
|
||||
|
||||
def _find_domains_or_certname(config, installer, question=None):
|
||||
@@ -512,7 +513,7 @@ def _report_new_cert(config, cert_path, fullchain_path, key_path=None):
|
||||
# and say something more informative here.
|
||||
msg = ('Congratulations! Your certificate and chain have been saved at:{br}'
|
||||
'{0}{br}{1}'
|
||||
'Your certificate will expire on {2}. To obtain a new or tweaked version of this '
|
||||
'Your cert will expire on {2}. To obtain a new or tweaked version of this '
|
||||
'certificate in the future, simply run {3} again{4}. '
|
||||
'To non-interactively renew *all* of your certificates, run "{3} renew"'
|
||||
.format(fullchain_path, privkey_statement, expiry, cli.cli_command, verbswitch,
|
||||
@@ -596,8 +597,8 @@ def _delete_if_appropriate(config):
|
||||
|
||||
attempt_deletion = config.delete_after_revoke
|
||||
if attempt_deletion is None:
|
||||
msg = ("Would you like to delete the certificate(s) you just revoked, "
|
||||
"along with all earlier and later versions of the certificate?")
|
||||
msg = ("Would you like to delete the cert(s) you just revoked, along with all earlier and "
|
||||
"later versions of the cert?")
|
||||
attempt_deletion = display.yesno(msg, yes_label="Yes (recommended)", no_label="No",
|
||||
force_interactive=True, default=True)
|
||||
|
||||
@@ -619,8 +620,8 @@ def _delete_if_appropriate(config):
|
||||
cert_manager.match_and_check_overlaps(config, [lambda x: archive_dir],
|
||||
lambda x: x.archive_dir, lambda x: x)
|
||||
except errors.OverlappingMatchFound:
|
||||
logger.warning("Not deleting revoked certificates due to overlapping archive dirs. "
|
||||
"More than one certificate is using %s", archive_dir)
|
||||
logger.warning("Not deleting revoked certs due to overlapping archive dirs. More than "
|
||||
"one certificate is using %s", archive_dir)
|
||||
return
|
||||
except Exception as e:
|
||||
msg = ('config.default_archive_dir: {0}, config.live_dir: {1}, archive_dir: {2},'
|
||||
@@ -665,7 +666,7 @@ def unregister(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -705,7 +706,7 @@ def register(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None` or a string indicating and error
|
||||
:rtype: None or str
|
||||
@@ -735,7 +736,7 @@ def update_account(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None` or a string indicating and error
|
||||
:rtype: None or str
|
||||
@@ -768,7 +769,7 @@ def update_account(config, unused_plugins):
|
||||
acc.regr = acc.regr.update(uri=prev_regr_uri)
|
||||
account_storage.update_regr(acc, cb_client.acme)
|
||||
|
||||
if not config.email:
|
||||
if config.email is None:
|
||||
display_util.notify("Any contact information associated "
|
||||
"with this account has been removed.")
|
||||
else:
|
||||
@@ -812,7 +813,7 @@ def install(config, plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param plugins: List of plugins
|
||||
:type plugins: plugins_disco.PluginsRegistry
|
||||
:type plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -895,7 +896,7 @@ def plugins_cmd(config, plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param plugins: List of plugins
|
||||
:type plugins: plugins_disco.PluginsRegistry
|
||||
:type plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -934,7 +935,7 @@ def enhance(config, plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param plugins: List of plugins
|
||||
:type plugins: plugins_disco.PluginsRegistry
|
||||
:type plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -993,7 +994,7 @@ def rollback(config, plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param plugins: List of plugins
|
||||
:type plugins: plugins_disco.PluginsRegistry
|
||||
:type plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -1011,7 +1012,7 @@ def update_symlinks(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -1029,7 +1030,7 @@ def rename(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -1047,7 +1048,7 @@ def delete(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -1063,7 +1064,7 @@ def certificates(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -1080,7 +1081,7 @@ def revoke(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None` or string indicating error in case of error
|
||||
:rtype: None or str
|
||||
@@ -1097,7 +1098,7 @@ def revoke(config, unused_plugins):
|
||||
raise errors.Error("Error! Exactly one of --cert-path or --cert-name must be specified!")
|
||||
|
||||
if config.key_path is not None: # revocation by cert key
|
||||
logger.debug("Revoking %s using certificate key %s",
|
||||
logger.debug("Revoking %s using cert key %s",
|
||||
config.cert_path[0], config.key_path[0])
|
||||
crypto_util.verify_cert_matches_priv_key(config.cert_path[0], config.key_path[0])
|
||||
key = jose.JWK.load(config.key_path[1])
|
||||
@@ -1125,7 +1126,7 @@ def run(config, plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param plugins: List of plugins
|
||||
:type plugins: plugins_disco.PluginsRegistry
|
||||
:type plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -1212,7 +1213,7 @@ def renew_cert(config, plugins, lineage):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param plugins: List of plugins
|
||||
:type plugins: plugins_disco.PluginsRegistry
|
||||
:type plugins: `list` of `str`
|
||||
|
||||
:param lineage: Certificate lineage object
|
||||
:type lineage: storage.RenewableCert
|
||||
@@ -1257,7 +1258,7 @@ def certonly(config, plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param plugins: List of plugins
|
||||
:type plugins: plugins_disco.PluginsRegistry
|
||||
:type plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -1307,7 +1308,7 @@ def renew(config, unused_plugins):
|
||||
:type config: interfaces.IConfig
|
||||
|
||||
:param unused_plugins: List of plugins (deprecated)
|
||||
:type unused_plugins: plugins_disco.PluginsRegistry
|
||||
:type unused_plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
@@ -1381,7 +1382,6 @@ def main(cli_args=None):
|
||||
|
||||
plugins = plugins_disco.PluginsRegistry.find_all()
|
||||
logger.debug("certbot version: %s", certbot.__version__)
|
||||
logger.debug("Location of certbot entry point: %s", sys.argv[0])
|
||||
# do not log `config`, as it contains sensitive data (e.g. revoke --key)!
|
||||
logger.debug("Arguments: %r", cli_args)
|
||||
logger.debug("Discovered plugins: %r", plugins)
|
||||
@@ -1403,6 +1403,13 @@ def main(cli_args=None):
|
||||
if config.func != plugins_cmd: # pylint: disable=comparison-with-callable
|
||||
raise
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
warnings.warn(
|
||||
"Python 2 support will be dropped in the next release of Certbot. "
|
||||
"Please upgrade your Python version.",
|
||||
PendingDeprecationWarning,
|
||||
) # pragma: no cover
|
||||
|
||||
set_displayer(config)
|
||||
|
||||
# Reporter
|
||||
|
||||
@@ -157,8 +157,7 @@ to serve all files under specified web root ({0})."""
|
||||
"--webroot-path and --domains, or --webroot-map. Run with "
|
||||
" --help webroot for examples.")
|
||||
for name, path in path_map.items():
|
||||
self.full_roots[name] = os.path.join(path, os.path.normcase(
|
||||
challenges.HTTP01.URI_ROOT_PATH))
|
||||
self.full_roots[name] = os.path.join(path, challenges.HTTP01.URI_ROOT_PATH)
|
||||
logger.debug("Creating root challenges validation dir at %s",
|
||||
self.full_roots[name])
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ def _reconstitute(config, full_path):
|
||||
config.domains = [util.enforce_domain_sanity(d)
|
||||
for d in renewal_candidate.names()]
|
||||
except errors.ConfigurationError as error:
|
||||
logger.warning("Renewal configuration file %s references a certificate "
|
||||
logger.warning("Renewal configuration file %s references a cert "
|
||||
"that contains an invalid domain name. The problem "
|
||||
"was: %s. Skipping.", full_path, error)
|
||||
return None
|
||||
@@ -293,13 +293,13 @@ def should_renew(config, lineage):
|
||||
|
||||
def _avoid_invalidating_lineage(config, lineage, original_server):
|
||||
"Do not renew a valid cert with one from a staging server!"
|
||||
# Some lineages may have begun with --staging, but then had production
|
||||
# certificates added to them
|
||||
# Some lineages may have begun with --staging, but then had production certs
|
||||
# added to them
|
||||
with open(lineage.cert) as the_file:
|
||||
contents = the_file.read()
|
||||
latest_cert = OpenSSL.crypto.load_certificate(
|
||||
OpenSSL.crypto.FILETYPE_PEM, contents)
|
||||
# all our test certificates are from happy hacker fake CA, though maybe one day
|
||||
# all our test certs are from happy hacker fake CA, though maybe one day
|
||||
# we should test more methodically
|
||||
now_valid = "fake" not in repr(latest_cert.get_issuer()).lower()
|
||||
|
||||
@@ -366,7 +366,7 @@ def _renew_describe_results(config, renew_successes, renew_failures,
|
||||
renewal_noun = "simulated renewal" if config.dry_run else "renewal"
|
||||
|
||||
if renew_skipped:
|
||||
notify("The following certificates are not due for renewal yet:")
|
||||
notify("The following certs are not due for renewal yet:")
|
||||
notify(report(renew_skipped, "skipped"))
|
||||
if not renew_successes and not renew_failures:
|
||||
notify("No {renewal}s were attempted.".format(renewal=renewal_noun))
|
||||
@@ -377,7 +377,7 @@ def _renew_describe_results(config, renew_successes, renew_failures,
|
||||
notify("Congratulations, all {renewal}s succeeded: ".format(renewal=renewal_noun))
|
||||
notify(report(renew_successes, "success"))
|
||||
elif renew_failures and not renew_successes:
|
||||
notify_error("All %ss failed. The following certificates could "
|
||||
notify_error("All %ss failed. The following certs could "
|
||||
"not be renewed:", renewal_noun)
|
||||
notify_error(report(renew_failures, "failure"))
|
||||
elif renew_failures and renew_successes:
|
||||
@@ -482,7 +482,7 @@ def handle_renewal_request(config):
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
# obtain_cert (presumably) encountered an unanticipated problem.
|
||||
logger.error(
|
||||
"Failed to renew certificate %s with error: %s",
|
||||
"Failed to renew cert %s with error: %s",
|
||||
lineagename, e
|
||||
)
|
||||
logger.debug("Traceback was:\n%s", traceback.format_exc())
|
||||
|
||||
@@ -214,7 +214,7 @@ def get_link_target(link):
|
||||
|
||||
"""
|
||||
try:
|
||||
target = filesystem.readlink(link)
|
||||
target = os.readlink(link)
|
||||
except OSError:
|
||||
raise errors.CertStorageError(
|
||||
"Expected {0} to be a symlink".format(link))
|
||||
@@ -223,7 +223,6 @@ def get_link_target(link):
|
||||
target = os.path.join(os.path.dirname(link), target)
|
||||
return os.path.abspath(target)
|
||||
|
||||
|
||||
def _write_live_readme_to(readme_path, is_base_dir=False):
|
||||
prefix = ""
|
||||
if is_base_dir:
|
||||
@@ -666,7 +665,7 @@ class RenewableCert(interfaces.RenewableCert):
|
||||
current_link = getattr(self, kind)
|
||||
if os.path.lexists(current_link):
|
||||
os.unlink(current_link)
|
||||
os.symlink(filesystem.readlink(previous_link), current_link)
|
||||
os.symlink(os.readlink(previous_link), current_link)
|
||||
|
||||
for _, link in previous_symlinks:
|
||||
if os.path.exists(link):
|
||||
@@ -810,8 +809,8 @@ class RenewableCert(interfaces.RenewableCert):
|
||||
May need to recover from rare interrupted / crashed states."""
|
||||
|
||||
if self.has_pending_deployment():
|
||||
logger.warning("Found a new certificate /archive/ that was not "
|
||||
"linked to in /live/; fixing...")
|
||||
logger.warning("Found a new cert /archive/ that was not linked to in /live/; "
|
||||
"fixing...")
|
||||
self.update_all_links_to(self.latest_common_version())
|
||||
return False
|
||||
return True
|
||||
@@ -847,7 +846,7 @@ class RenewableCert(interfaces.RenewableCert):
|
||||
link = getattr(self, kind)
|
||||
filename = "{0}{1}.pem".format(kind, version)
|
||||
# Relative rather than absolute target directory
|
||||
target_directory = os.path.dirname(filesystem.readlink(link))
|
||||
target_directory = os.path.dirname(os.readlink(link))
|
||||
# TODO: it could be safer to make the link first under a temporary
|
||||
# filename, then unlink the old link, then rename the new link
|
||||
# to the old link; this ensures that this process is able to
|
||||
@@ -884,7 +883,7 @@ class RenewableCert(interfaces.RenewableCert):
|
||||
"""
|
||||
target = self.current_target("cert")
|
||||
if target is None:
|
||||
raise errors.CertStorageError("could not find the certificate file")
|
||||
raise errors.CertStorageError("could not find cert file")
|
||||
with open(target) as f:
|
||||
return crypto_util.get_names_from_cert(f.read())
|
||||
|
||||
@@ -1122,7 +1121,7 @@ class RenewableCert(interfaces.RenewableCert):
|
||||
# The behavior below keeps the prior key by creating a new
|
||||
# symlink to the old key or the target of the old key symlink.
|
||||
if os.path.islink(old_privkey):
|
||||
old_privkey = filesystem.readlink(old_privkey)
|
||||
old_privkey = os.readlink(old_privkey)
|
||||
else:
|
||||
old_privkey = "privkey{0}.pem".format(prior_version)
|
||||
logger.debug("Writing symlink to old private key, %s.", old_privkey)
|
||||
|
||||
@@ -18,7 +18,7 @@ def run_generic_updaters(config, lineage, plugins):
|
||||
:type lineage: storage.RenewableCert
|
||||
|
||||
:param plugins: List of plugins
|
||||
:type plugins: certbot._internal.plugins.disco.PluginsRegistry
|
||||
:type plugins: `list` of `str`
|
||||
|
||||
:returns: `None`
|
||||
:rtype: None
|
||||
|
||||
@@ -33,7 +33,7 @@ class AnnotatedChallenge(jose.ImmutableMap):
|
||||
Wraps around server provided challenge and annotates with data
|
||||
useful for the client.
|
||||
|
||||
:ivar ~.challb: Wrapped `~.ChallengeBody`.
|
||||
:ivar challb: Wrapped `~.ChallengeBody`.
|
||||
|
||||
"""
|
||||
__slots__ = ('challb',)
|
||||
|
||||
@@ -4,7 +4,6 @@ from __future__ import absolute_import
|
||||
import errno
|
||||
import os # pylint: disable=os-module-forbidden
|
||||
import stat
|
||||
import sys
|
||||
|
||||
from acme.magic_typing import List
|
||||
|
||||
@@ -362,8 +361,7 @@ def realpath(file_path):
|
||||
"""
|
||||
original_path = file_path
|
||||
|
||||
# Since Python 3.8, os.path.realpath also resolves symlinks on Windows.
|
||||
if POSIX_MODE or sys.version_info >= (3, 8):
|
||||
if POSIX_MODE:
|
||||
path = os.path.realpath(file_path)
|
||||
if os.path.islink(path):
|
||||
# If path returned by realpath is still a link, it means that it failed to
|
||||
@@ -385,36 +383,8 @@ def realpath(file_path):
|
||||
return os.path.abspath(file_path)
|
||||
|
||||
|
||||
def readlink(link_path):
|
||||
# type: (str) -> str
|
||||
"""
|
||||
Return a string representing the path to which the symbolic link points.
|
||||
|
||||
:param str link_path: The symlink path to resolve
|
||||
:return: The path the symlink points to
|
||||
:returns: str
|
||||
:raise: ValueError if a long path (260> characters) is encountered on Windows
|
||||
"""
|
||||
path = os.readlink(link_path)
|
||||
|
||||
if POSIX_MODE or not path.startswith('\\\\?\\'):
|
||||
return path
|
||||
|
||||
# At this point, we know we are on Windows and that the path returned uses
|
||||
# the extended form which is done for all paths in Python 3.8+
|
||||
|
||||
# Max length of a normal path is 260 characters on Windows, including the non printable
|
||||
# termination character "<NUL>". The termination character is not included in Python
|
||||
# strings, giving a max length of 259 characters, + 4 characters for the extended form
|
||||
# prefix, to an effective max length 263 characters on a string representing a normal path.
|
||||
if len(path) < 264:
|
||||
return path[4:]
|
||||
|
||||
raise ValueError("Long paths are not supported by Certbot on Windows.")
|
||||
|
||||
|
||||
# On Windows is_executable run from an unprivileged shell may claim that a path is
|
||||
# executable when it is executable only if run from a privileged shell. This result
|
||||
# executable when it is excutable only if run from a privileged shell. This result
|
||||
# is due to the fact that GetEffectiveRightsFromAcl calculate effective rights
|
||||
# without taking into consideration if the target user has currently required the
|
||||
# elevated privileges or not. However this is not a problem since certbot always
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user