Compare commits
70 Commits
travis-tes
...
test-snaps
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0421da79e | ||
|
|
132ab7b517 | ||
|
|
ebf1349b15 | ||
|
|
9d2e0ac013 | ||
|
|
05dbda4b51 | ||
|
|
68b3b048b9 | ||
|
|
d434b92945 | ||
|
|
f82e2cc714 | ||
|
|
433c6f391c | ||
|
|
590eeca38a | ||
|
|
b9a25c3987 | ||
|
|
41b99eba79 | ||
|
|
de39a42e6a | ||
|
|
183ccc64b1 | ||
|
|
6bca930752 | ||
|
|
cd993cdfb1 | ||
|
|
9f994d7a50 | ||
|
|
4f3dc8862d | ||
|
|
48139f382d | ||
|
|
8a3a8c7097 | ||
|
|
cb3ff9ef18 | ||
|
|
f743dbec3a | ||
|
|
2af297d72f | ||
|
|
95ef53e5d5 | ||
|
|
24c5fab8b6 | ||
|
|
713b91495b | ||
|
|
0f4c31c9c7 | ||
|
|
b9a8248541 | ||
|
|
8027430625 | ||
|
|
bce14ae65f | ||
|
|
25d1977d4f | ||
|
|
46eb4ec7e3 | ||
|
|
3ae8fa640b | ||
|
|
035b6514db | ||
|
|
f151099342 | ||
|
|
25e79e4aca | ||
|
|
db064a4109 | ||
|
|
860af81fef | ||
|
|
70c8481fd8 | ||
|
|
c5e5594ac3 | ||
|
|
ad8ffc1bf0 | ||
|
|
29a23d3148 | ||
|
|
44b1bd8e0e | ||
|
|
0bebdedcbc | ||
|
|
8ccc96bbdd | ||
|
|
4a2618d415 | ||
|
|
bcb3554836 | ||
|
|
0f53e8ad4e | ||
|
|
2a18ae6d57 | ||
|
|
3c4b922197 | ||
|
|
0bb1f0b2ce | ||
|
|
ba192f321d | ||
|
|
961c573864 | ||
|
|
fb39de7d01 | ||
|
|
97fcfd40d1 | ||
|
|
9ac476e87b | ||
|
|
8d776fb7ac | ||
|
|
50fa04ba0c | ||
|
|
e31834a6cd | ||
|
|
340a4280ea | ||
|
|
cc07722b3e | ||
|
|
67bcf0f6bd | ||
|
|
1b2328f18b | ||
|
|
560b9e5012 | ||
|
|
2f6fbe9987 | ||
|
|
bebcad0588 | ||
|
|
92f26367eb | ||
|
|
d135e6140b | ||
|
|
010b38fa10 | ||
|
|
8a15bd7927 |
@@ -1,13 +1,13 @@
|
||||
# Advanced pipeline for running our full test suite on demand.
|
||||
# Advanced pipeline for running our full test suite on demand and for release branches.
|
||||
trigger:
|
||||
- '*.x'
|
||||
# When changing these triggers, please ensure the documentation under
|
||||
# "Running tests in CI" is still correct.
|
||||
- azure-test-*
|
||||
- test-*
|
||||
pr: none
|
||||
|
||||
jobs:
|
||||
# Any addition here should be reflected in the advanced and release pipelines.
|
||||
# It is advised to declare all jobs here as templates to improve maintainability.
|
||||
- template: templates/tests-suite.yml
|
||||
- template: templates/installer-tests.yml
|
||||
stages:
|
||||
- template: templates/stages/test-and-package-stage.yml
|
||||
# Notify failures only for release branches.
|
||||
- ${{ if not(startsWith(variables['Build.SourceBranchName'], 'test-')) }}:
|
||||
- template: templates/stages/notify-failure-stage.yml
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# Advanced pipeline for running our full test suite on protected branches.
|
||||
trigger:
|
||||
- '*.x'
|
||||
pr: none
|
||||
# This pipeline is also nightly run on master
|
||||
schedules:
|
||||
- cron: "0 4 * * *"
|
||||
displayName: Nightly build
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
always: true
|
||||
|
||||
jobs:
|
||||
# Any addition here should be reflected in the advanced-test and release pipelines.
|
||||
# It is advised to declare all jobs here as templates to improve maintainability.
|
||||
- template: templates/tests-suite.yml
|
||||
- template: templates/installer-tests.yml
|
||||
@@ -1,8 +1,7 @@
|
||||
trigger:
|
||||
- master
|
||||
trigger: none
|
||||
pr:
|
||||
- master
|
||||
- '*.x'
|
||||
|
||||
jobs:
|
||||
- template: templates/tests-suite.yml
|
||||
- template: templates/jobs/standard-tests-jobs.yml
|
||||
|
||||
15
.azure-pipelines/nightly.yml
Normal file
15
.azure-pipelines/nightly.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
# Nightly pipeline running each day for master.
|
||||
trigger: none
|
||||
pr: none
|
||||
schedules:
|
||||
- cron: "30 4 * * *"
|
||||
displayName: Nightly build
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
always: true
|
||||
|
||||
stages:
|
||||
- template: templates/stages/test-and-package-stage.yml
|
||||
- template: templates/stages/deploy-stage.yml
|
||||
- template: templates/stages/notify-failure-stage.yml
|
||||
@@ -5,9 +5,8 @@ trigger:
|
||||
- v*
|
||||
pr: none
|
||||
|
||||
jobs:
|
||||
# Any addition here should be reflected in the advanced and advanced-test pipelines.
|
||||
# It is advised to declare all jobs here as templates to improve maintainability.
|
||||
- template: templates/tests-suite.yml
|
||||
- template: templates/installer-tests.yml
|
||||
- template: templates/changelog.yml
|
||||
stages:
|
||||
- template: templates/stages/test-and-package-stage.yml
|
||||
- template: templates/stages/changelog-stage.yml
|
||||
- template: templates/stages/deploy-stage.yml
|
||||
- template: templates/stages/notify-failure-stage.yml
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
jobs:
|
||||
- job: changelog
|
||||
pool:
|
||||
vmImage: vs2017-win2016
|
||||
steps:
|
||||
- bash: |
|
||||
CERTBOT_VERSION="$(cd certbot && python -c "import certbot; print(certbot.__version__)" && cd ~-)"
|
||||
"${BUILD_REPOSITORY_LOCALPATH}\tools\extract_changelog.py" "${CERTBOT_VERSION}" >> "${BUILD_ARTIFACTSTAGINGDIRECTORY}/release_notes.md"
|
||||
displayName: Prepare changelog
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
artifact: changelog
|
||||
displayName: Publish changelog
|
||||
@@ -1,61 +0,0 @@
|
||||
jobs:
|
||||
- job: installer_build
|
||||
pool:
|
||||
vmImage: vs2017-win2016
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: 3.7
|
||||
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)
|
||||
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: |
|
||||
$currentVersion = $PSVersionTable.PSVersion
|
||||
if ($currentVersion.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: |
|
||||
py -3 -m venv venv
|
||||
venv\Scripts\python tools\pip_install.py -e certbot-ci
|
||||
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
|
||||
96
.azure-pipelines/templates/jobs/extended-tests-jobs.yml
Normal file
96
.azure-pipelines/templates/jobs/extended-tests-jobs.yml
Normal file
@@ -0,0 +1,96 @@
|
||||
jobs:
|
||||
- job: extended_test
|
||||
variables:
|
||||
- name: IMAGE_NAME
|
||||
value: ubuntu-18.04
|
||||
- group: certbot-common
|
||||
strategy:
|
||||
matrix:
|
||||
linux-py36:
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: py36
|
||||
linux-py37:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: py37
|
||||
linux-py37-nopin:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: py37
|
||||
CERTBOT_NO_PIN: 1
|
||||
linux-boulder-v1-integration-certbot-oldest:
|
||||
TOXENV: integration-certbot-oldest
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-integration-certbot-oldest:
|
||||
TOXENV: integration-certbot-oldest
|
||||
ACME_SERVER: boulder-v2
|
||||
linux-boulder-v1-integration-nginx-oldest:
|
||||
TOXENV: integration-nginx-oldest
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-integration-nginx-oldest:
|
||||
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-py35-integration:
|
||||
PYTHON_VERSION: 3.5
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-py35-integration:
|
||||
PYTHON_VERSION: 3.5
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v2
|
||||
linux-boulder-v1-py36-integration:
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-py36-integration:
|
||||
PYTHON_VERSION: 3.6
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v2
|
||||
linux-boulder-v1-py37-integration:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-py37-integration:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v2
|
||||
linux-boulder-v1-py38-integration:
|
||||
PYTHON_VERSION: 3.8
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v1
|
||||
linux-boulder-v2-py38-integration:
|
||||
PYTHON_VERSION: 3.8
|
||||
TOXENV: integration
|
||||
ACME_SERVER: boulder-v2
|
||||
nginx-compat:
|
||||
TOXENV: nginx_compat
|
||||
le-auto-jessie:
|
||||
TOXENV: le_auto_jessie
|
||||
le-auto-centos6:
|
||||
TOXENV: le_auto_centos6
|
||||
le-auto-oraclelinux6:
|
||||
TOXENV: le_auto_oraclelinux6
|
||||
docker-dev:
|
||||
TOXENV: docker_dev
|
||||
farmtest-apache2:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: test-farm-apache2
|
||||
farmtest-leauto-upgrades:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: test-farm-leauto-upgrades
|
||||
farmtest-certonly-standalone:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: test-farm-certonly-standalone
|
||||
farmtest-sdists:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: test-farm-sdists
|
||||
pool:
|
||||
vmImage: $(IMAGE_NAME)
|
||||
steps:
|
||||
- template: ../steps/tox-steps.yml
|
||||
96
.azure-pipelines/templates/jobs/packaging-jobs.yml
Normal file
96
.azure-pipelines/templates/jobs/packaging-jobs.yml
Normal file
@@ -0,0 +1,96 @@
|
||||
jobs:
|
||||
- job: snap_build
|
||||
strategy:
|
||||
matrix:
|
||||
amd64:
|
||||
arch: amd64
|
||||
armhf:
|
||||
arch: armhf
|
||||
arm64:
|
||||
arch: arm64
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
steps:
|
||||
- script: |
|
||||
tools/snap/build.sh ${ARCH}
|
||||
mv *.snap $(Build.ArtifactStagingDirectory)
|
||||
displayName: Build Certbot snap
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
artifact: snap-$(arch)
|
||||
displayName: Store snap artifact
|
||||
- job: snap_dns_build
|
||||
strategy:
|
||||
matrix:
|
||||
amd64:
|
||||
arch: amd64
|
||||
armhf:
|
||||
arch: armhf
|
||||
arm64:
|
||||
arch: arm64
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
steps:
|
||||
- script: |
|
||||
tools/snap/build_dns.sh ${ARCH} ALL
|
||||
mv certbot-dns-*/*.snap $(Build.ArtifactStagingDirectory)
|
||||
displayName: Build Certbot DNS snaps
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
artifact: dns-snap-$(arch)
|
||||
displayName: Store snaps artifacts
|
||||
- job: snap_run
|
||||
dependsOn: snap_build
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
steps:
|
||||
- script: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends nginx-light snapd
|
||||
python tools/pip_install.py -U tox
|
||||
displayName: Install dependencies
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: snap-amd64
|
||||
path: $(Build.SourcesDirectory)/snap
|
||||
displayName: Retrieve Certbot snap
|
||||
- script: |
|
||||
sudo snap install --dangerous --classic snap/*.snap
|
||||
displayName: Install Certbot snap
|
||||
- script: |
|
||||
python -m tox -e integration-external,apacheconftest-external-with-pebble
|
||||
displayName: Run tox
|
||||
- job: snap_dns_run
|
||||
dependsOn:
|
||||
- snap_build
|
||||
- snap_dns_build
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
steps:
|
||||
- script: |
|
||||
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: snap-amd64
|
||||
path: $(Build.SourcesDirectory)/snap
|
||||
displayName: Retrieve Certbot snap
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: dns-snap-amd64
|
||||
path: $(Build.SourcesDirectory)/snap
|
||||
displayName: Retrieve Certbot DNS plugins snaps
|
||||
- script: |
|
||||
python3 -m venv venv
|
||||
venv/bin/python tools/pip_install.py -e certbot-ci
|
||||
displayName: Prepare Certbot-CI
|
||||
- script: |
|
||||
sudo -E venv/bin/pytest certbot-ci/snap_integration_tests/dns_tests --allow-persistent-changes --snap-folder $(Build.SourcesDirectory)/snap
|
||||
displayName: Test DNS plugins snaps
|
||||
73
.azure-pipelines/templates/jobs/standard-tests-jobs.yml
Normal file
73
.azure-pipelines/templates/jobs/standard-tests-jobs.yml
Normal file
@@ -0,0 +1,73 @@
|
||||
jobs:
|
||||
- job: test
|
||||
strategy:
|
||||
matrix:
|
||||
macos-py27:
|
||||
IMAGE_NAME: macOS-10.14
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: py27
|
||||
macos-py38:
|
||||
IMAGE_NAME: macOS-10.14
|
||||
PYTHON_VERSION: 3.8
|
||||
TOXENV: py38
|
||||
windows-py35:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.5
|
||||
TOXENV: py35
|
||||
windows-py37-cover:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: py37-cover
|
||||
windows-integration-certbot:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: integration-certbot
|
||||
linux-oldest-tests-1:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
TOXENV: py27-{acme,apache,apache-v2,certbot}-oldest
|
||||
linux-oldest-tests-2:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
TOXENV: py27-{dns,nginx}-oldest
|
||||
linux-py27:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: py27
|
||||
linux-py35:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.5
|
||||
TOXENV: py35
|
||||
linux-py38-cover:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.8
|
||||
TOXENV: py38-cover
|
||||
linux-py37-lint:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: lint
|
||||
linux-py35-mypy:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 3.5
|
||||
TOXENV: mypy
|
||||
linux-integration:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: integration
|
||||
ACME_SERVER: pebble
|
||||
apache-compat:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
TOXENV: apache_compat
|
||||
le-auto-xenial:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
TOXENV: le_auto_xenial
|
||||
apacheconftest:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: apacheconftest-with-pebble
|
||||
nginxroundtrip:
|
||||
IMAGE_NAME: ubuntu-18.04
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: nginxroundtrip
|
||||
pool:
|
||||
vmImage: $(IMAGE_NAME)
|
||||
steps:
|
||||
- template: ../steps/tox-steps.yml
|
||||
16
.azure-pipelines/templates/stages/changelog-stage.yml
Normal file
16
.azure-pipelines/templates/stages/changelog-stage.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
stages:
|
||||
- stage: Changelog
|
||||
jobs:
|
||||
- job: prepare
|
||||
pool:
|
||||
vmImage: vs2017-win2016
|
||||
steps:
|
||||
- bash: |
|
||||
CERTBOT_VERSION="$(cd certbot && python -c "import certbot; print(certbot.__version__)" && cd ~-)"
|
||||
"${BUILD_REPOSITORY_LOCALPATH}\tools\extract_changelog.py" "${CERTBOT_VERSION}" >> "${BUILD_ARTIFACTSTAGINGDIRECTORY}/release_notes.md"
|
||||
displayName: Prepare changelog
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
artifact: changelog
|
||||
displayName: Publish changelog
|
||||
50
.azure-pipelines/templates/stages/deploy-stage.yml
Normal file
50
.azure-pipelines/templates/stages/deploy-stage.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
stages:
|
||||
- stage: Deploy
|
||||
jobs:
|
||||
# This job relies on a snapcraft.cfg preconfigured with credential,
|
||||
# stored as a secure file in Azure Pipeline.
|
||||
# This credential has a maximum lifetime of 1 year and the current
|
||||
# credential will expire on 6/25/2021. The content of snapcraft.cfg
|
||||
# will need to be updated to use a new credential before then to
|
||||
# prevent automated deploys from breaking. Remembering to do this is
|
||||
# also tracked by https://github.com/certbot/certbot/issues/7931.
|
||||
- job: publish_snap
|
||||
strategy:
|
||||
matrix:
|
||||
amd64:
|
||||
ARCH: amd64
|
||||
arm64:
|
||||
ARCH: arm64
|
||||
armhf:
|
||||
ARCH: armhf
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
variables:
|
||||
- group: certbot-common
|
||||
steps:
|
||||
- bash: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends snapd
|
||||
sudo snap install --classic snapcraft
|
||||
displayName: Install dependencies
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: snap-$(arch)
|
||||
path: $(Build.SourcesDirectory)/snap
|
||||
displayName: Retrieve Certbot snap
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: dns-snap-$(arch)
|
||||
path: $(Build.SourcesDirectory)/snap
|
||||
displayName: Retrieve DNS plugins snaps
|
||||
- task: DownloadSecureFile@1
|
||||
name: snapcraftCfg
|
||||
inputs:
|
||||
secureFile: snapcraft.cfg
|
||||
- bash: |
|
||||
mkdir -p .snapcraft
|
||||
ln -s $(snapcraftCfg.secureFilePath) .snapcraft/snapcraft.cfg
|
||||
for SNAP_FILE in snap/*.snap; do
|
||||
snapcraft upload --release=edge "${SNAP_FILE}"
|
||||
done
|
||||
displayName: Publish to Snap store
|
||||
18
.azure-pipelines/templates/stages/notify-failure-stage.yml
Normal file
18
.azure-pipelines/templates/stages/notify-failure-stage.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
stages:
|
||||
- stage: On_Failure
|
||||
jobs:
|
||||
- job: notify_mattermost
|
||||
variables:
|
||||
- group: certbot-common
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- bash: |
|
||||
MESSAGE="\
|
||||
---\n\
|
||||
##### Azure Pipeline
|
||||
*Repo* $(Build.Repository.ID) - *Pipeline* $(Build.DefinitionName) #$(Build.BuildNumber) - *Branch/PR* $(Build.SourceBranchName)\n\
|
||||
:warning: __Pipeline has failed__: [Link to the build](https://dev.azure.com/$(Build.Repository.ID)/_build/results?buildId=$(Build.BuildId)&view=results)\n\n\
|
||||
---"
|
||||
curl -i -X POST --data-urlencode "payload={\"text\":\"${MESSAGE}\"}" "$(MATTERMOST_URL)"
|
||||
condition: failed()
|
||||
@@ -0,0 +1,4 @@
|
||||
stages:
|
||||
- stage: TestAndPackage
|
||||
jobs:
|
||||
- template: ../jobs/packaging-jobs.yml
|
||||
53
.azure-pipelines/templates/steps/tox-steps.yml
Normal file
53
.azure-pipelines/templates/steps/tox-steps.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
steps:
|
||||
- bash: |
|
||||
brew install augeas
|
||||
condition: startswith(variables['IMAGE_NAME'], 'macOS')
|
||||
displayName: Install MacOS dependencies
|
||||
- bash: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
python-dev \
|
||||
gcc \
|
||||
libaugeas0 \
|
||||
libssl-dev \
|
||||
libffi-dev \
|
||||
ca-certificates \
|
||||
nginx-light \
|
||||
openssl
|
||||
sudo systemctl stop nginx
|
||||
condition: startswith(variables['IMAGE_NAME'], 'ubuntu')
|
||||
displayName: Install Linux dependencies
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: $(PYTHON_VERSION)
|
||||
addToPath: true
|
||||
condition: ne(variables['PYTHON_VERSION'], '')
|
||||
# tools/pip_install.py is used to pin packages to a known working version
|
||||
# except in tests where the environment variable CERTBOT_NO_PIN is set.
|
||||
# virtualenv is listed here explicitly to make sure it is upgraded when
|
||||
# CERTBOT_NO_PIN is set to work around failures we've seen when using an older
|
||||
# version of virtualenv. The option "-I" is set so when CERTBOT_NO_PIN is also
|
||||
# set, pip updates dependencies it thinks are already satisfied to avoid some
|
||||
# problems with its lack of real dependency resolution.
|
||||
- bash: |
|
||||
python tools/pip_install.py -I tox virtualenv
|
||||
displayName: Install runtime dependencies
|
||||
- task: DownloadSecureFile@1
|
||||
name: testFarmPem
|
||||
inputs:
|
||||
secureFile: azure-test-farm.pem
|
||||
condition: contains(variables['TOXENV'], 'test-farm')
|
||||
- bash: |
|
||||
export TARGET_BRANCH="`echo "${BUILD_SOURCEBRANCH}" | sed -E 's!refs/(heads|tags)/!!g'`"
|
||||
[ -z "${SYSTEM_PULLREQUEST_TARGETBRANCH}" ] || export TARGET_BRANCH="${SYSTEM_PULLREQUEST_TARGETBRANCH}"
|
||||
env
|
||||
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)
|
||||
AWS_EC2_PEM_FILE: $(testFarmPem.secureFilePath)
|
||||
displayName: Run tox
|
||||
@@ -1,39 +0,0 @@
|
||||
jobs:
|
||||
- job: test
|
||||
strategy:
|
||||
matrix:
|
||||
macos-py27:
|
||||
IMAGE_NAME: macOS-10.14
|
||||
PYTHON_VERSION: 2.7
|
||||
TOXENV: py27
|
||||
macos-py38:
|
||||
IMAGE_NAME: macOS-10.14
|
||||
PYTHON_VERSION: 3.8
|
||||
TOXENV: py38
|
||||
windows-py35:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.5
|
||||
TOXENV: py35
|
||||
windows-py37-cover:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: py37-cover
|
||||
windows-integration-certbot:
|
||||
IMAGE_NAME: vs2017-win2016
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: integration-certbot
|
||||
PYTEST_ADDOPTS: --numprocesses 4
|
||||
pool:
|
||||
vmImage: $(IMAGE_NAME)
|
||||
steps:
|
||||
- bash: brew install augeas
|
||||
condition: startswith(variables['IMAGE_NAME'], 'macOS')
|
||||
displayName: Install Augeas
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: $(PYTHON_VERSION)
|
||||
addToPath: true
|
||||
- script: python tools/pip_install.py -U tox coverage
|
||||
displayName: Install dependencies
|
||||
- script: python -m tox
|
||||
displayName: Run tox
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -58,3 +58,5 @@ parts
|
||||
prime
|
||||
stage
|
||||
*.snap
|
||||
snap-constraints.txt
|
||||
qemu-*
|
||||
|
||||
321
.travis.yml
321
.travis.yml
@@ -1,321 +0,0 @@
|
||||
language: python
|
||||
dist: xenial
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/pip
|
||||
|
||||
before_script:
|
||||
# On Travis, the fastest parallelization for integration tests has proved to be 4.
|
||||
- 'if [[ "$TOXENV" == *"integration"* ]]; then export PYTEST_ADDOPTS="--numprocesses 4"; fi'
|
||||
# Use Travis retry feature for farm tests since they are flaky
|
||||
- 'if [[ "$TOXENV" == "travis-test-farm"* ]]; then export TRAVIS_RETRY=travis_retry; fi'
|
||||
- export TOX_TESTENV_PASSENV=TRAVIS
|
||||
- 'if [[ "$SNAP" == true ]]; then snap/local/build_and_install.sh; fi'
|
||||
|
||||
# Only build pushes to the master branch, PRs, and branches beginning with
|
||||
# `test-`, `travis-test-`, or of the form `digit(s).digit(s).x` or
|
||||
# `vdigit(s).digit(s).digit(s)`. As documented at
|
||||
# https://docs.travis-ci.com/user/customizing-the-build/#safelisting-or-blocklisting-branches,
|
||||
# this includes tags so pushing tags of the form `vdigit(s).digit(s).digit(s)`
|
||||
# will also trigger tests. This reduces the number of simultaneous Travis runs,
|
||||
# which speeds turnaround time on review since there is a cap of on the number
|
||||
# of simultaneous runs.
|
||||
branches:
|
||||
# When changing these branches, please ensure the documentation under
|
||||
# "Running tests in CI" is still correct.
|
||||
only:
|
||||
- master
|
||||
- /^\d+\.\d+\.x$/ # this matches our point release branches
|
||||
- /^v\d+\.\d+\.\d+$/ # this matches our release tags
|
||||
- /^(travis-)?test-.*$/
|
||||
|
||||
# Jobs for the main test suite are always executed (including on PRs) except for pushes on master.
|
||||
not-on-master: ¬-on-master
|
||||
if: NOT (type = push AND branch = master)
|
||||
|
||||
# Jobs for the extended test suite are executed for cron jobs and pushes to
|
||||
# non-development branches.
|
||||
extended-test-suite: &extended-test-suite
|
||||
if: type = cron OR (type = push AND branch != master)
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Main test suite
|
||||
- stage: "Test"
|
||||
python: "2.7"
|
||||
env: ACME_SERVER=pebble TOXENV=integration
|
||||
<<: *not-on-master
|
||||
|
||||
# As documented at
|
||||
# https://docs.travis-ci.com/user/build-stages/#how-to-define-build-stages,
|
||||
# the previous stage will be automatically applied to all subsequent jobs
|
||||
# until a new stage is defined.
|
||||
|
||||
# This job is always executed, including on master
|
||||
- python: "3.8"
|
||||
env: TOXENV=py38-cover FYI="py38 tests + code coverage"
|
||||
|
||||
- python: "3.7"
|
||||
env: TOXENV=lint
|
||||
<<: *not-on-master
|
||||
- python: "3.5"
|
||||
env: TOXENV=mypy
|
||||
<<: *not-on-master
|
||||
- python: "2.7"
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
env: TOXENV='py27-{acme,apache,apache-v2,certbot,dns,nginx}-oldest'
|
||||
<<: *not-on-master
|
||||
- python: "2.7"
|
||||
env: TOXENV=py27
|
||||
<<: *not-on-master
|
||||
- python: "3.5"
|
||||
env: TOXENV=py35
|
||||
<<: *not-on-master
|
||||
- sudo: required
|
||||
env: TOXENV=apache_compat
|
||||
services: docker
|
||||
addons:
|
||||
<<: *not-on-master
|
||||
- sudo: required
|
||||
env: TOXENV=le_auto_xenial
|
||||
services: docker
|
||||
<<: *not-on-master
|
||||
- python: "2.7"
|
||||
env: TOXENV=apacheconftest-with-pebble
|
||||
<<: *not-on-master
|
||||
- python: "2.7"
|
||||
env: TOXENV=nginxroundtrip
|
||||
<<: *not-on-master
|
||||
|
||||
# Extended test suite on cron jobs and pushes to tested branches other than master
|
||||
- sudo: required
|
||||
env: TOXENV=nginx_compat
|
||||
services: docker
|
||||
addons:
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
env:
|
||||
- TOXENV=travis-test-farm-apache2
|
||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
env:
|
||||
- TOXENV=travis-test-farm-leauto-upgrades
|
||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
||||
git:
|
||||
depth: false # This is needed to have the history to checkout old versions of certbot-auto.
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
env:
|
||||
- TOXENV=travis-test-farm-certonly-standalone
|
||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
env:
|
||||
- TOXENV=travis-test-farm-sdists
|
||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
env: TOXENV=py37 CERTBOT_NO_PIN=1
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration-certbot-oldest
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration-certbot-oldest
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration-nginx-oldest
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration-nginx-oldest
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.6"
|
||||
env: TOXENV=py36
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
env: TOXENV=py37
|
||||
<<: *extended-test-suite
|
||||
- python: "3.5"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.5"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.6"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.6"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.8"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||
<<: *extended-test-suite
|
||||
- python: "3.8"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration
|
||||
<<: *extended-test-suite
|
||||
- sudo: required
|
||||
env: TOXENV=le_auto_jessie
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- sudo: required
|
||||
env: TOXENV=le_auto_centos6
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- sudo: required
|
||||
env: TOXENV=le_auto_oraclelinux6
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- sudo: required
|
||||
env: TOXENV=docker_dev
|
||||
services: docker
|
||||
addons:
|
||||
apt:
|
||||
packages: # don't install nginx and apache
|
||||
- libaugeas0
|
||||
<<: *extended-test-suite
|
||||
- stage: "Snap"
|
||||
sudo: required
|
||||
env: SNAP=true TOXENV=integration-external,apacheconftest-external-with-pebble
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- nginx-light
|
||||
snaps:
|
||||
- name: snapcraft
|
||||
channel: stable
|
||||
confinement: classic
|
||||
- name: lxd
|
||||
channel: stable
|
||||
git:
|
||||
# By default, Travis clones the repo to a depth of 50 commits which can
|
||||
# break the ability to use `git describe` to set the version of the
|
||||
# snap. This setting removes the --depth flag from git commands solving
|
||||
# this problem. See
|
||||
# https://docs.travis-ci.com/user/customizing-the-build#git-clone-depth
|
||||
# for more info.
|
||||
depth: false
|
||||
deploy:
|
||||
# This section relies on credentials stored in a SNAP_TOKEN environment
|
||||
# variable in Travis. See
|
||||
# https://docs.travis-ci.com/user/deployment/snaps/ for more info.
|
||||
# This credential has a maximum lifetime of 1 year and the current
|
||||
# credential will expire on 4/22/2021. The value of SNAP_TOKEN will
|
||||
# need to be updated to use a new credential before then to prevent
|
||||
# automated deploys from breaking. Remembering to do this is also
|
||||
# tracked by https://github.com/certbot/certbot/issues/7931.
|
||||
'on':
|
||||
# Deploy on release tags or nightly runs from any branch. We only try
|
||||
# to deploy from the certbot/certbot repo to prevent errors if forks
|
||||
# of this repo try to run tests.
|
||||
all_branches: true
|
||||
condition: -n $TRAVIS_TAG || $TRAVIS_EVENT_TYPE = cron
|
||||
repo: certbot/certbot
|
||||
provider: snap
|
||||
snap: certbot_*.snap
|
||||
channel: edge
|
||||
# skip_cleanup is needed to prevent Travis from deleting the snaps we
|
||||
# just built and tested. See
|
||||
# https://docs.travis-ci.com/user/deployment#uploading-files-and-skip_cleanup.
|
||||
skip_cleanup: true
|
||||
<<: *extended-test-suite
|
||||
|
||||
# container-based infrastructure
|
||||
sudo: false
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages: # Keep in sync with letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh and Boulder.
|
||||
- python-dev
|
||||
- gcc
|
||||
- libaugeas0
|
||||
- libssl-dev
|
||||
- libffi-dev
|
||||
- ca-certificates
|
||||
# For certbot-nginx integration testing
|
||||
- nginx-light
|
||||
- openssl
|
||||
|
||||
# tools/pip_install.py is used to pin packages to a known working version
|
||||
# except in tests where the environment variable CERTBOT_NO_PIN is set.
|
||||
# virtualenv is listed here explicitly to make sure it is upgraded when
|
||||
# CERTBOT_NO_PIN is set to work around failures we've seen when using an older
|
||||
# version of virtualenv. The option "-I" is set so when CERTBOT_NO_PIN is also
|
||||
# set, pip updates dependencies it thinks are already satisfied to avoid some
|
||||
# problems with its lack of real dependency resolution.
|
||||
install: 'tools/pip_install.py -I tox virtualenv'
|
||||
# Most of the time TRAVIS_RETRY is an empty string, and has no effect on the
|
||||
# script command. It is set only to `travis_retry` during farm tests, in
|
||||
# order to trigger the Travis retry feature, and compensate the inherent
|
||||
# flakiness of these specific tests.
|
||||
script: '$TRAVIS_RETRY tox'
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
if: NOT branch =~ ^(travis-)?test-.*$
|
||||
channels:
|
||||
# This is set to a secure variable to prevent forks from sending
|
||||
# notifications. This value was created by installing
|
||||
# https://github.com/travis-ci/travis.rb and running
|
||||
# `travis encrypt "chat.freenode.net#certbot-devel"`.
|
||||
- secure: "EWW66E2+KVPZyIPR8ViENZwfcup4Gx3/dlimmAZE0WuLwxDCshBBOd3O8Rf6pBokEoZlXM5eDT6XdyJj8n0DLslgjO62pExdunXpbcMwdY7l1ELxX2/UbnDTE6UnPYa09qVBHNG7156Z6yE0x2lH4M9Ykvp0G0cubjPQHylAwo0="
|
||||
on_cancel: never
|
||||
on_success: never
|
||||
on_failure: always
|
||||
@@ -36,7 +36,8 @@ Authors
|
||||
* [Blake Griffith](https://github.com/cowlicks)
|
||||
* [Brad Warren](https://github.com/bmw)
|
||||
* [Brandon Kraft](https://github.com/kraftbj)
|
||||
* [Brandon Kreisel](https://github.com/kraftbj)
|
||||
* [Brandon Kreisel](https://github.com/BKreisel)
|
||||
* [Brian Heim](https://github.com/brianlheim)
|
||||
* [Cameron Steel](https://github.com/Tugzrida)
|
||||
* [Ceesjan Luiten](https://github.com/quinox)
|
||||
* [Chad Whitacre](https://github.com/whit537)
|
||||
@@ -84,6 +85,7 @@ Authors
|
||||
* [Felix Schwarz](https://github.com/FelixSchwarz)
|
||||
* [Felix Yan](https://github.com/felixonmars)
|
||||
* [Filip Ochnik](https://github.com/filipochnik)
|
||||
* [Florian Klink](https://github.com/flokli)
|
||||
* [Francois Marier](https://github.com/fmarier)
|
||||
* [Frank](https://github.com/Frankkkkk)
|
||||
* [Frederic BLANC](https://github.com/fblanc)
|
||||
@@ -202,6 +204,7 @@ Authors
|
||||
* [Pierre Jaury](https://github.com/kaiyou)
|
||||
* [Piotr Kasprzyk](https://github.com/kwadrat)
|
||||
* [Prayag Verma](https://github.com/pra85)
|
||||
* [Rasesh Patel](https://github.com/raspat1)
|
||||
* [Reinaldo de Souza Jr](https://github.com/juniorz)
|
||||
* [Remi Rampin](https://github.com/remram44)
|
||||
* [Rémy HUBSCHER](https://github.com/Natim)
|
||||
|
||||
@@ -13,6 +13,7 @@ import josepy as jose
|
||||
import OpenSSL
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
from requests.utils import parse_header_links
|
||||
from requests_toolbelt.adapters.source import SourceAddressAdapter
|
||||
import six
|
||||
from six.moves import http_client
|
||||
@@ -733,11 +734,13 @@ class ClientV2(ClientBase):
|
||||
raise errors.ValidationError(failed)
|
||||
return orderr.update(authorizations=responses)
|
||||
|
||||
def finalize_order(self, orderr, deadline):
|
||||
def finalize_order(self, orderr, deadline, fetch_alternative_chains=False):
|
||||
"""Finalize an order and obtain a certificate.
|
||||
|
||||
:param messages.OrderResource orderr: order to finalize
|
||||
:param datetime.datetime deadline: when to stop polling and timeout
|
||||
:param bool fetch_alternative_chains: whether to also fetch alternative
|
||||
certificate chains
|
||||
|
||||
:returns: finalized order
|
||||
:rtype: messages.OrderResource
|
||||
@@ -754,8 +757,13 @@ class ClientV2(ClientBase):
|
||||
if body.error is not None:
|
||||
raise errors.IssuanceError(body.error)
|
||||
if body.certificate is not None:
|
||||
certificate_response = self._post_as_get(body.certificate).text
|
||||
return orderr.update(body=body, fullchain_pem=certificate_response)
|
||||
certificate_response = self._post_as_get(body.certificate)
|
||||
orderr = orderr.update(body=body, fullchain_pem=certificate_response.text)
|
||||
if fetch_alternative_chains:
|
||||
alt_chains_urls = self._get_links(certificate_response, 'alternate')
|
||||
alt_chains = [self._post_as_get(url).text for url in alt_chains_urls]
|
||||
orderr = orderr.update(alternative_fullchains_pem=alt_chains)
|
||||
return orderr
|
||||
raise errors.TimeoutError()
|
||||
|
||||
def revoke(self, cert, rsn):
|
||||
@@ -785,6 +793,20 @@ class ClientV2(ClientBase):
|
||||
new_args = args[:1] + (None,) + args[1:]
|
||||
return self._post(*new_args, **kwargs)
|
||||
|
||||
def _get_links(self, response, relation_type):
|
||||
"""
|
||||
Retrieves all Link URIs of relation_type from the response.
|
||||
:param requests.Response response: The requests HTTP response.
|
||||
:param str relation_type: The relation type to filter by.
|
||||
"""
|
||||
# Can't use response.links directly because it drops multiple links
|
||||
# of the same relation type, which is possible in RFC8555 responses.
|
||||
if not 'Link' in response.headers:
|
||||
return []
|
||||
links = parse_header_links(response.headers['Link'])
|
||||
return [l['url'] for l in links
|
||||
if 'rel' in l and 'url' in l and l['rel'] == relation_type]
|
||||
|
||||
|
||||
class BackwardsCompatibleClientV2(object):
|
||||
"""ACME client wrapper that tends towards V2-style calls, but
|
||||
@@ -863,11 +885,13 @@ class BackwardsCompatibleClientV2(object):
|
||||
return messages.OrderResource(authorizations=authorizations, csr_pem=csr_pem)
|
||||
return self.client.new_order(csr_pem)
|
||||
|
||||
def finalize_order(self, orderr, deadline):
|
||||
def finalize_order(self, orderr, deadline, fetch_alternative_chains=False):
|
||||
"""Finalize an order and obtain a certificate.
|
||||
|
||||
:param messages.OrderResource orderr: order to finalize
|
||||
:param datetime.datetime deadline: when to stop polling and timeout
|
||||
:param bool fetch_alternative_chains: whether to also fetch alternative
|
||||
certificate chains
|
||||
|
||||
:returns: finalized order
|
||||
:rtype: messages.OrderResource
|
||||
@@ -898,7 +922,7 @@ class BackwardsCompatibleClientV2(object):
|
||||
chain = crypto_util.dump_pyopenssl_chain(chain).decode()
|
||||
|
||||
return orderr.update(fullchain_pem=(cert + chain))
|
||||
return self.client.finalize_order(orderr, deadline)
|
||||
return self.client.finalize_order(orderr, deadline, fetch_alternative_chains)
|
||||
|
||||
def revoke(self, cert, rsn):
|
||||
"""Revoke certificate.
|
||||
|
||||
@@ -566,9 +566,11 @@ class Revocation(ResourceMixin, jose.JSONObjectWithFields):
|
||||
class Order(ResourceBody):
|
||||
"""Order Resource Body.
|
||||
|
||||
:ivar list of .Identifier: List of identifiers for the certificate.
|
||||
:ivar identifiers: List of identifiers for the certificate.
|
||||
:vartype identifiers: `list` of `.Identifier`
|
||||
:ivar acme.messages.Status status:
|
||||
:ivar list of str authorizations: URLs of authorizations.
|
||||
:ivar authorizations: URLs of authorizations.
|
||||
:vartype authorizations: `list` of `str`
|
||||
:ivar str certificate: URL to download certificate as a fullchain PEM.
|
||||
:ivar str finalize: URL to POST to to request issuance once all
|
||||
authorizations have "valid" status.
|
||||
@@ -593,15 +595,20 @@ class OrderResource(ResourceWithURI):
|
||||
|
||||
:ivar acme.messages.Order body:
|
||||
:ivar str csr_pem: The CSR this Order will be finalized with.
|
||||
:ivar list of acme.messages.AuthorizationResource authorizations:
|
||||
Fully-fetched AuthorizationResource objects.
|
||||
:ivar authorizations: Fully-fetched AuthorizationResource objects.
|
||||
:vartype authorizations: `list` of `acme.messages.AuthorizationResource`
|
||||
:ivar str fullchain_pem: The fetched contents of the certificate URL
|
||||
produced once the order was finalized, if it's present.
|
||||
:ivar alternative_fullchains_pem: The fetched contents of alternative certificate
|
||||
chain URLs produced once the order was finalized, if present and requested during
|
||||
finalization.
|
||||
:vartype alternative_fullchains_pem: `list` of `str`
|
||||
"""
|
||||
body = jose.Field('body', decoder=Order.from_json)
|
||||
csr_pem = jose.Field('csr_pem', omitempty=True)
|
||||
authorizations = jose.Field('authorizations')
|
||||
fullchain_pem = jose.Field('fullchain_pem', omitempty=True)
|
||||
alternative_fullchains_pem = jose.Field('alternative_fullchains_pem', omitempty=True)
|
||||
|
||||
@Directory.register
|
||||
class NewOrder(Order):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,7 +6,7 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
@@ -17,8 +17,8 @@ install_requires = [
|
||||
# 1.1.0+ is required to avoid the warnings described at
|
||||
# https://github.com/certbot/josepy/issues/13.
|
||||
'josepy>=1.1.0',
|
||||
# Connection.set_tlsext_host_name (>=0.13)
|
||||
'PyOpenSSL>=0.13.1',
|
||||
# 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
|
||||
@@ -27,7 +27,7 @@ install_requires = [
|
||||
'six>=1.9.0', # needed for python_2_unicode_compatible
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
@@ -263,7 +263,7 @@ class BackwardsCompatibleClientV2Test(ClientTestBase):
|
||||
with mock.patch('acme.client.ClientV2') as mock_client:
|
||||
client = self._init()
|
||||
client.finalize_order(mock_orderr, mock_deadline)
|
||||
mock_client().finalize_order.assert_called_once_with(mock_orderr, mock_deadline)
|
||||
mock_client().finalize_order.assert_called_once_with(mock_orderr, mock_deadline, False)
|
||||
|
||||
def test_revoke(self):
|
||||
self.response.json.return_value = DIRECTORY_V1.to_json()
|
||||
@@ -842,6 +842,32 @@ class ClientV2Test(ClientTestBase):
|
||||
deadline = datetime.datetime.now() - datetime.timedelta(seconds=60)
|
||||
self.assertRaises(errors.TimeoutError, self.client.finalize_order, self.orderr, deadline)
|
||||
|
||||
def test_finalize_order_alt_chains(self):
|
||||
updated_order = self.order.update(
|
||||
certificate='https://www.letsencrypt-demo.org/acme/cert/',
|
||||
)
|
||||
updated_orderr = self.orderr.update(body=updated_order,
|
||||
fullchain_pem=CERT_SAN_PEM,
|
||||
alternative_fullchains_pem=[CERT_SAN_PEM,
|
||||
CERT_SAN_PEM])
|
||||
self.response.json.return_value = updated_order.to_json()
|
||||
self.response.text = CERT_SAN_PEM
|
||||
self.response.headers['Link'] ='<https://example.com/acme/cert/1>;rel="alternate", ' + \
|
||||
'<https://exaple.com/dir>;rel="index", ' + \
|
||||
'<https://example.com/acme/cert/2>;title="foo";rel="alternate"'
|
||||
|
||||
deadline = datetime.datetime(9999, 9, 9)
|
||||
resp = self.client.finalize_order(self.orderr, deadline, fetch_alternative_chains=True)
|
||||
self.net.post.assert_any_call('https://example.com/acme/cert/1',
|
||||
mock.ANY, acme_version=2, new_nonce_url=mock.ANY)
|
||||
self.net.post.assert_any_call('https://example.com/acme/cert/2',
|
||||
mock.ANY, acme_version=2, new_nonce_url=mock.ANY)
|
||||
self.assertEqual(resp, updated_orderr)
|
||||
|
||||
del self.response.headers['Link']
|
||||
resp = self.client.finalize_order(self.orderr, deadline, fetch_alternative_chains=True)
|
||||
self.assertEqual(resp, updated_orderr.update(alternative_fullchains_pem=[]))
|
||||
|
||||
def test_revoke(self):
|
||||
self.client.revoke(messages_test.CERT, self.rsn)
|
||||
self.net.post.assert_called_once_with(
|
||||
|
||||
@@ -225,7 +225,8 @@ def _get_runtime_cfg(command):
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
universal_newlines=True,
|
||||
env=util.env_no_snap_for_external_calls())
|
||||
stdout, stderr = proc.communicate()
|
||||
|
||||
except (OSError, ValueError):
|
||||
|
||||
@@ -115,6 +115,7 @@ class ApacheConfigurator(common.Installer):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/apache2",
|
||||
bin=None
|
||||
)
|
||||
|
||||
def option(self, key):
|
||||
@@ -145,7 +146,7 @@ class ApacheConfigurator(common.Installer):
|
||||
"""
|
||||
opts = ["enmod", "dismod", "le_vhost_ext", "server_root", "vhost_root",
|
||||
"logs_root", "challenge_location", "handle_modules", "handle_sites",
|
||||
"ctl"]
|
||||
"ctl", "bin"]
|
||||
for o in opts:
|
||||
# Config options use dashes instead of underscores
|
||||
if self.conf(o.replace("_", "-")) is not None:
|
||||
@@ -194,6 +195,8 @@ class ApacheConfigurator(common.Installer):
|
||||
"(Only Ubuntu/Debian currently)")
|
||||
add("ctl", default=DEFAULTS["ctl"],
|
||||
help="Full path to Apache control script")
|
||||
add("bin", default=DEFAULTS["bin"],
|
||||
help="Full path to apache2/httpd binary")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize an Apache Configurator.
|
||||
@@ -269,18 +272,25 @@ class ApacheConfigurator(common.Installer):
|
||||
"""
|
||||
if self._openssl_version:
|
||||
return self._openssl_version
|
||||
# Step 1. Check for LoadModule directive
|
||||
# Step 1. Determine the location of ssl_module
|
||||
try:
|
||||
ssl_module_location = self.parser.modules['ssl_module']
|
||||
except KeyError:
|
||||
if warn_on_no_mod_ssl:
|
||||
logger.warning("Could not find ssl_module; not disabling session tickets.")
|
||||
return None
|
||||
if not ssl_module_location:
|
||||
logger.warning("Could not find ssl_module; not disabling session tickets.")
|
||||
return None
|
||||
ssl_module_location = self.parser.standard_path_from_server_root(ssl_module_location)
|
||||
# Step 2. Grep in the .so for openssl version
|
||||
if ssl_module_location:
|
||||
# Possibility A: ssl_module is a DSO
|
||||
ssl_module_location = self.parser.standard_path_from_server_root(ssl_module_location)
|
||||
else:
|
||||
# Possibility B: ssl_module is statically linked into Apache
|
||||
if self.option("bin"):
|
||||
ssl_module_location = self.option("bin")
|
||||
else:
|
||||
logger.warning("ssl_module is statically linked but --apache-bin is "
|
||||
"missing; not disabling session tickets.")
|
||||
return None
|
||||
# Step 2. Grep in the binary for openssl version
|
||||
contents = self._open_module_file(ssl_module_location)
|
||||
if not contents:
|
||||
logger.warning("Unable to read ssl_module file; not disabling session tickets.")
|
||||
|
||||
@@ -169,7 +169,7 @@ class ApacheHttp01(common.ChallengePerformer):
|
||||
|
||||
def _set_up_challenges(self):
|
||||
if not os.path.isdir(self.challenge_dir):
|
||||
old_umask = os.umask(0o022)
|
||||
old_umask = filesystem.umask(0o022)
|
||||
try:
|
||||
filesystem.makedirs(self.challenge_dir, 0o755)
|
||||
except OSError as exception:
|
||||
@@ -177,7 +177,7 @@ class ApacheHttp01(common.ChallengePerformer):
|
||||
raise errors.PluginError(
|
||||
"Couldn't create root for http-01 challenge")
|
||||
finally:
|
||||
os.umask(old_umask)
|
||||
filesystem.umask(old_umask)
|
||||
|
||||
responses = []
|
||||
for achall in self.achalls:
|
||||
|
||||
@@ -24,4 +24,5 @@ class ArchConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/httpd/conf",
|
||||
bin=None,
|
||||
)
|
||||
|
||||
@@ -35,6 +35,7 @@ class CentOSConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/httpd/conf.d",
|
||||
bin=None,
|
||||
)
|
||||
|
||||
def config_test(self):
|
||||
|
||||
@@ -24,4 +24,5 @@ class DarwinConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/apache2/other",
|
||||
bin=None,
|
||||
)
|
||||
|
||||
@@ -33,6 +33,7 @@ class DebianConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=True,
|
||||
handle_sites=True,
|
||||
challenge_location="/etc/apache2",
|
||||
bin=None,
|
||||
)
|
||||
|
||||
def enable_site(self, vhost):
|
||||
|
||||
@@ -29,6 +29,7 @@ class FedoraConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/httpd/conf.d",
|
||||
bin=None,
|
||||
)
|
||||
|
||||
def config_test(self):
|
||||
|
||||
@@ -27,6 +27,7 @@ class GentooConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/apache2/vhosts.d",
|
||||
bin=None,
|
||||
)
|
||||
|
||||
def _prepare_options(self):
|
||||
|
||||
@@ -24,4 +24,5 @@ class OpenSUSEConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/apache2/vhosts.d",
|
||||
bin=None,
|
||||
)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
certbot[dev]==1.1.0
|
||||
certbot[dev]==1.6.0
|
||||
@@ -1,4 +1,4 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,20 +6,20 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
'certbot>=1.6.0',
|
||||
'python-augeas',
|
||||
'setuptools',
|
||||
'zope.component',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
@@ -1772,12 +1772,22 @@ class InstallSslOptionsConfTest(util.ApacheTest):
|
||||
AH02556: "SSLOpenSSLConfCmd %s %s" applied to %s
|
||||
OpenSSL 1.0.2g 1 Mar 2016
|
||||
"""
|
||||
# ssl_module as a DSO
|
||||
self.config.parser.modules['ssl_module'] = '/fake/path'
|
||||
with mock.patch("certbot_apache._internal.configurator."
|
||||
"ApacheConfigurator._open_module_file") as mock_omf:
|
||||
mock_omf.return_value = some_string_contents
|
||||
self.assertEqual(self.config.openssl_version(), "1.0.2g")
|
||||
|
||||
# ssl_module statically linked
|
||||
self.config._openssl_version = None
|
||||
self.config.parser.modules['ssl_module'] = None
|
||||
self.config.options['bin'] = '/fake/path/to/httpd'
|
||||
with mock.patch("certbot_apache._internal.configurator."
|
||||
"ApacheConfigurator._open_module_file") as mock_omf:
|
||||
mock_omf.return_value = some_string_contents
|
||||
self.assertEqual(self.config.openssl_version(), "1.0.2g")
|
||||
|
||||
def test_current_version(self):
|
||||
self.config.version = (2, 4, 10)
|
||||
self.config._openssl_version = '1.0.2m'
|
||||
@@ -1799,12 +1809,21 @@ class InstallSslOptionsConfTest(util.ApacheTest):
|
||||
self.assertEqual(self.config.openssl_version(), None)
|
||||
self.assertTrue("Could not find ssl_module" in mock_log.call_args[0][0])
|
||||
|
||||
# When no ssl_module is present at all
|
||||
self.config._openssl_version = None
|
||||
self.config.parser.modules['ssl_module'] = None
|
||||
self.assertTrue("ssl_module" not in self.config.parser.modules)
|
||||
with mock.patch("certbot_apache._internal.configurator.logger.warning") as mock_log:
|
||||
self.assertEqual(self.config.openssl_version(), None)
|
||||
self.assertTrue("Could not find ssl_module" in mock_log.call_args[0][0])
|
||||
|
||||
# When ssl_module is statically linked but --apache-bin not provided
|
||||
self.config._openssl_version = None
|
||||
self.config.options['bin'] = None
|
||||
self.config.parser.modules['ssl_module'] = None
|
||||
with mock.patch("certbot_apache._internal.configurator.logger.warning") as mock_log:
|
||||
self.assertEqual(self.config.openssl_version(), None)
|
||||
self.assertTrue("ssl_module is statically linked but" in mock_log.call_args[0][0])
|
||||
|
||||
self.config.parser.modules['ssl_module'] = "/fake/path"
|
||||
with mock.patch("certbot_apache._internal.configurator.logger.warning") as mock_log:
|
||||
# Check that correct logger.warning was printed
|
||||
|
||||
417
certbot-auto
417
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.5.0"
|
||||
LE_AUTO_VERSION="1.6.0"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
@@ -1265,45 +1265,40 @@ if [ "$1" = "--le-auto-phase2" ]; then
|
||||
# pip install hashin
|
||||
# hashin -r dependency-requirements.txt cryptography==1.5.2
|
||||
# ```
|
||||
ConfigArgParse==1.0 \
|
||||
--hash=sha256:bf378245bc9cdc403a527e5b7406b991680c2a530e7e81af747880b54eb57133
|
||||
certifi==2019.11.28 \
|
||||
--hash=sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3 \
|
||||
--hash=sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f
|
||||
cffi==1.13.2 \
|
||||
--hash=sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42 \
|
||||
--hash=sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04 \
|
||||
--hash=sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5 \
|
||||
--hash=sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54 \
|
||||
--hash=sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba \
|
||||
--hash=sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57 \
|
||||
--hash=sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396 \
|
||||
--hash=sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12 \
|
||||
--hash=sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97 \
|
||||
--hash=sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43 \
|
||||
--hash=sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db \
|
||||
--hash=sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3 \
|
||||
--hash=sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b \
|
||||
--hash=sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579 \
|
||||
--hash=sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346 \
|
||||
--hash=sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159 \
|
||||
--hash=sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652 \
|
||||
--hash=sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e \
|
||||
--hash=sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a \
|
||||
--hash=sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506 \
|
||||
--hash=sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f \
|
||||
--hash=sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d \
|
||||
--hash=sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c \
|
||||
--hash=sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20 \
|
||||
--hash=sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858 \
|
||||
--hash=sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc \
|
||||
--hash=sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a \
|
||||
--hash=sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3 \
|
||||
--hash=sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e \
|
||||
--hash=sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410 \
|
||||
--hash=sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25 \
|
||||
--hash=sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b \
|
||||
--hash=sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d
|
||||
ConfigArgParse==1.2.3 \
|
||||
--hash=sha256:edd17be986d5c1ba2e307150b8e5f5107aba125f3574dddd02c85d5cdcfd37dc
|
||||
certifi==2020.4.5.1 \
|
||||
--hash=sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304 \
|
||||
--hash=sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519
|
||||
cffi==1.14.0 \
|
||||
--hash=sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff \
|
||||
--hash=sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b \
|
||||
--hash=sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac \
|
||||
--hash=sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0 \
|
||||
--hash=sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384 \
|
||||
--hash=sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26 \
|
||||
--hash=sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6 \
|
||||
--hash=sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b \
|
||||
--hash=sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e \
|
||||
--hash=sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd \
|
||||
--hash=sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2 \
|
||||
--hash=sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66 \
|
||||
--hash=sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc \
|
||||
--hash=sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8 \
|
||||
--hash=sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55 \
|
||||
--hash=sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4 \
|
||||
--hash=sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5 \
|
||||
--hash=sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d \
|
||||
--hash=sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78 \
|
||||
--hash=sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa \
|
||||
--hash=sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793 \
|
||||
--hash=sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f \
|
||||
--hash=sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a \
|
||||
--hash=sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f \
|
||||
--hash=sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30 \
|
||||
--hash=sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f \
|
||||
--hash=sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3 \
|
||||
--hash=sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c
|
||||
chardet==3.0.4 \
|
||||
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
|
||||
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
|
||||
@@ -1331,67 +1326,66 @@ cryptography==2.8 \
|
||||
--hash=sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2 \
|
||||
--hash=sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf \
|
||||
--hash=sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8
|
||||
distro==1.4.0 \
|
||||
--hash=sha256:362dde65d846d23baee4b5c058c8586f219b5a54be1cf5fc6ff55c4578392f57 \
|
||||
--hash=sha256:eedf82a470ebe7d010f1872c17237c79ab04097948800029994fa458e52fb4b4
|
||||
# Package enum34 needs to be explicitly limited to Python2.x, in order to avoid
|
||||
# certbot-auto failures on Python 3.6+ which enum34 doesn't support. See #5456.
|
||||
enum34==1.1.6 ; python_version < '3.4' \
|
||||
--hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
|
||||
--hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
|
||||
--hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
|
||||
--hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1
|
||||
distro==1.5.0 \
|
||||
--hash=sha256:0e58756ae38fbd8fc3020d54badb8eae17c5b9dcbed388b17bb55b8a5928df92 \
|
||||
--hash=sha256:df74eed763e18d10d0da624258524ae80486432cd17392d9c3d96f5e83cd2799
|
||||
enum34==1.1.10; python_version < '3.4' \
|
||||
--hash=sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53 \
|
||||
--hash=sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328 \
|
||||
--hash=sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248
|
||||
funcsigs==1.0.2 \
|
||||
--hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \
|
||||
--hash=sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50
|
||||
idna==2.8 \
|
||||
--hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \
|
||||
--hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
|
||||
idna==2.9 \
|
||||
--hash=sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb \
|
||||
--hash=sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa
|
||||
ipaddress==1.0.23 \
|
||||
--hash=sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc \
|
||||
--hash=sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2
|
||||
josepy==1.2.0 \
|
||||
--hash=sha256:8ea15573203f28653c00f4ac0142520777b1c59d9eddd8da3f256c6ba3cac916 \
|
||||
--hash=sha256:9cec9a839fe9520f0420e4f38e7219525daccce4813296627436fe444cd002d3
|
||||
josepy==1.3.0 \
|
||||
--hash=sha256:c341ffa403399b18e9eae9012f804843045764d1390f9cb4648980a7569b1619 \
|
||||
--hash=sha256:e54882c64be12a2a76533f73d33cba9e331950fda9e2731e843490b774e7a01c
|
||||
mock==1.3.0 \
|
||||
--hash=sha256:1e247dbecc6ce057299eb7ee019ad68314bb93152e81d9a6110d35f4d5eca0f6 \
|
||||
--hash=sha256:3f573a18be94de886d1191f27c168427ef693e8dcfcecf95b170577b2eb69cbb
|
||||
parsedatetime==2.5 \
|
||||
--hash=sha256:3b835fc54e472c17ef447be37458b400e3fefdf14bb1ffdedb5d2c853acf4ba1 \
|
||||
--hash=sha256:d2e9ddb1e463de871d32088a3f3cea3dc8282b1b2800e081bd0ef86900451667
|
||||
pbr==5.4.4 \
|
||||
--hash=sha256:139d2625547dbfa5fb0b81daebb39601c478c21956dc57e2e07b74450a8c506b \
|
||||
--hash=sha256:61aa52a0f18b71c5cc58232d2cf8f8d09cd67fcad60b742a60124cb8d6951488
|
||||
pbr==5.4.5 \
|
||||
--hash=sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c \
|
||||
--hash=sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8
|
||||
pyOpenSSL==19.1.0 \
|
||||
--hash=sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504 \
|
||||
--hash=sha256:9a24494b2602aaf402be5c9e30a0b82d4a5c67528fe8fb475e3f3bc00dd69507
|
||||
pyRFC3339==1.1 \
|
||||
--hash=sha256:67196cb83b470709c580bb4738b83165e67c6cc60e1f2e4f286cfcb402a926f4 \
|
||||
--hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
|
||||
pycparser==2.19 \
|
||||
--hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
|
||||
pyparsing==2.4.6 \
|
||||
--hash=sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f \
|
||||
--hash=sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec
|
||||
pycparser==2.20 \
|
||||
--hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \
|
||||
--hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705
|
||||
pyparsing==2.4.7 \
|
||||
--hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \
|
||||
--hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b
|
||||
python-augeas==0.5.0 \
|
||||
--hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2
|
||||
pytz==2019.3 \
|
||||
--hash=sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d \
|
||||
--hash=sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be
|
||||
requests==2.22.0 \
|
||||
--hash=sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4 \
|
||||
--hash=sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31
|
||||
pytz==2020.1 \
|
||||
--hash=sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed \
|
||||
--hash=sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048
|
||||
requests==2.23.0 \
|
||||
--hash=sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee \
|
||||
--hash=sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6
|
||||
requests-toolbelt==0.9.1 \
|
||||
--hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \
|
||||
--hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0
|
||||
six==1.14.0 \
|
||||
--hash=sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a \
|
||||
--hash=sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c
|
||||
urllib3==1.25.8 \
|
||||
--hash=sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc \
|
||||
--hash=sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc
|
||||
zope.component==4.6 \
|
||||
--hash=sha256:ec2afc5bbe611dcace98bb39822c122d44743d635dafc7315b9aef25097db9e6
|
||||
six==1.15.0 \
|
||||
--hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \
|
||||
--hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced
|
||||
urllib3==1.25.9 \
|
||||
--hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \
|
||||
--hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115
|
||||
zope.component==4.6.1 \
|
||||
--hash=sha256:bfbe55d4a93e70a78b10edc3aad4de31bb8860919b7cbd8d66f717f7d7b279ac \
|
||||
--hash=sha256:d9c7c27673d787faff8a83797ce34d6ebcae26a370e25bddb465ac2182766aca
|
||||
zope.deferredimport==4.3.1 \
|
||||
--hash=sha256:57b2345e7b5eef47efcd4f634ff16c93e4265de3dcf325afc7315ade48d909e1 \
|
||||
--hash=sha256:9a0c211df44aa95f1c4e6d2626f90b400f56989180d3ef96032d708da3d23e0a
|
||||
@@ -1401,126 +1395,129 @@ zope.deprecation==4.4.0 \
|
||||
zope.event==4.4 \
|
||||
--hash=sha256:69c27debad9bdacd9ce9b735dad382142281ac770c4a432b533d6d65c4614bcf \
|
||||
--hash=sha256:d8e97d165fd5a0997b45f5303ae11ea3338becfe68c401dd88ffd2113fe5cae7
|
||||
zope.hookable==5.0.0 \
|
||||
--hash=sha256:0992a0dd692003c09fb958e1480cebd1a28f2ef32faa4857d864f3ca8e9d6952 \
|
||||
--hash=sha256:0f325838dbac827a1e2ed5d482c1f2656b6844dc96aa098f7727e76395fcd694 \
|
||||
--hash=sha256:22a317ba00f61bac99eac1a5e330be7cb8c316275a21269ec58aa396b602af0c \
|
||||
--hash=sha256:25531cb5e7b35e8a6d1d6eddef624b9a22ce5dcf8f4448ef0f165acfa8c3fc21 \
|
||||
--hash=sha256:30890892652766fc80d11f078aca9a5b8150bef6b88aba23799581a53515c404 \
|
||||
--hash=sha256:342d682d93937e5b8c232baffb32a87d5eee605d44f74566657c64a239b7f342 \
|
||||
--hash=sha256:46b2fddf1f5aeb526e02b91f7e62afbb9fff4ffd7aafc97cdb00a0d717641567 \
|
||||
--hash=sha256:523318ff96df9b8d378d997c00c5d4cbfbff68dc48ff5ee5addabdb697d27528 \
|
||||
--hash=sha256:53aa02eb8921d4e667c69d76adeed8fe426e43870c101cb08dcd2f3468aff742 \
|
||||
--hash=sha256:62e79e8fdde087cb20822d7874758f5acbedbffaf3c0fbe06309eb8a41ee4e06 \
|
||||
--hash=sha256:74bf2f757f7385b56dc3548adae508d8b3ef952d600b4b12b88f7d1706b05dcc \
|
||||
--hash=sha256:751ee9d89eb96e00c1d7048da9725ce392a708ed43406416dc5ed61e4d199764 \
|
||||
--hash=sha256:7b83bc341e682771fe810b360cd5d9c886a948976aea4b979ff214e10b8b523b \
|
||||
--hash=sha256:81eeeb27dbb0ddaed8070daee529f0d1bfe4f74c7351cce2aaca3ea287c4cc32 \
|
||||
--hash=sha256:856509191e16930335af4d773c0fc31a17bae8991eb6f167a09d5eddf25b56cc \
|
||||
--hash=sha256:8853e81fd07b18fa9193b19e070dc0557848d9945b1d2dac3b7782543458c87d \
|
||||
--hash=sha256:94506a732da2832029aecdfe6ea07eb1b70ee06d802fff34e1b3618fe7cdf026 \
|
||||
--hash=sha256:95ad874a8cc94e786969215d660143817f745225579bfe318c4676e218d3147c \
|
||||
--hash=sha256:9758ec9174966ffe5c499b6c3d149f80aa0a9238020006a2b87c6af5963fcf48 \
|
||||
--hash=sha256:a169823e331da939aa7178fc152e65699aeb78957e46c6f80ccb50ee4c3616c2 \
|
||||
--hash=sha256:a67878a798f6ca292729a28c2226592b3d000dc6ee7825d31887b553686c7ac7 \
|
||||
--hash=sha256:a9a6d9eb2319a09905670810e2de971d6c49013843700b4975e2fc0afe96c8db \
|
||||
--hash=sha256:b3e118b58a3d2301960e6f5f25736d92f6b9f861728d3b8c26d69f54d8a157d2 \
|
||||
--hash=sha256:ca6705c2a1fb5059a4efbe9f5426be4cdf71b3c9564816916fc7aa7902f19ede \
|
||||
--hash=sha256:cf711527c9d4ae72085f137caffb4be74fc007ffb17cd103628c7d5ba17e205f \
|
||||
--hash=sha256:d087602a6845ebe9d5a1c5a949fedde2c45f372d77fbce4f7fe44b68b28a1d03 \
|
||||
--hash=sha256:d1080e1074ddf75ad6662a9b34626650759c19a9093e1a32a503d37e48da135b \
|
||||
--hash=sha256:db9c60368aff2b7e6c47115f3ad9bd6e96aa298b12ed5f8cb13f5673b30be565 \
|
||||
--hash=sha256:dbeb127a04473f5a989169eb400b67beb921c749599b77650941c21fe39cb8d9 \
|
||||
--hash=sha256:dca336ca3682d869d291d7cd18284f6ff6876e4244eb1821430323056b000e2c \
|
||||
--hash=sha256:dd69a9be95346d10c853b6233fcafe3c0315b89424b378f2ad45170d8e161568 \
|
||||
--hash=sha256:dd79f8fae5894f1ee0a0042214685f2d039341250c994b825c10a4cd075d80f6 \
|
||||
--hash=sha256:e647d850aa1286d98910133cee12bd87c354f7b7bb3f3cd816a62ba7fa2f7007 \
|
||||
--hash=sha256:f37a210b5c04b2d4e4bac494ab15b70196f219a1e1649ddca78560757d4278fb \
|
||||
--hash=sha256:f67820b6d33a705dc3c1c457156e51686f7b350ff57f2112e1a9a4dad38ec268 \
|
||||
--hash=sha256:f68969978ccf0e6123902f7365aae5b7a9e99169d4b9105c47cf28e788116894 \
|
||||
--hash=sha256:f717a0b34460ae1ac0064e91b267c0588ac2c098ffd695992e72cd5462d97a67 \
|
||||
--hash=sha256:f9d58ccec8684ca276d5a4e7b0dfacca028336300a8f715d616d9f0ce9ae8096 \
|
||||
--hash=sha256:fcc3513a54e656067cbf7b98bab0d6b9534b9eabc666d1f78aad6acdf0962736
|
||||
zope.interface==4.7.1 \
|
||||
--hash=sha256:048b16ac882a05bc7ef534e8b9f15c9d7a6c190e24e8938a19b7617af4ed854a \
|
||||
--hash=sha256:05816cf8e7407cf62f2ec95c0a5d69ec4fa5741d9ccd10db9f21691916a9a098 \
|
||||
--hash=sha256:065d6a1ac89d35445168813bed45048ed4e67a4cdfc5a68fdb626a770378869f \
|
||||
--hash=sha256:14157421f4121a57625002cc4f48ac7521ea238d697c4a4459a884b62132b977 \
|
||||
--hash=sha256:18dc895945694f397a0be86be760ff664b790f95d8e7752d5bab80284ff9105d \
|
||||
--hash=sha256:1962c9f838bd6ae4075d0014f72697510daefc7e1c7e48b2607df0b6e157989c \
|
||||
--hash=sha256:1a67408cacd198c7e6274a19920bb4568d56459e659e23c4915528686ac1763a \
|
||||
--hash=sha256:21bf781076dd616bd07cf0223f79d61ab4f45176076f90bc2890e18c48195da4 \
|
||||
--hash=sha256:21c0a5d98650aebb84efa16ce2c8df1a46bdc4fe8a9e33237d0ca0b23f416ead \
|
||||
--hash=sha256:23cfeea25d1e42ff3bf4f9a0c31e9d5950aa9e7c4b12f0c4bd086f378f7b7a71 \
|
||||
--hash=sha256:24b6fce1fb71abf9f4093e3259084efcc0ef479f89356757780685bd2b06ef37 \
|
||||
--hash=sha256:24f84ce24eb6b5fcdcb38ad9761524f1ae96f7126abb5e597f8a3973d9921409 \
|
||||
--hash=sha256:25e0ef4a824017809d6d8b0ce4ab3288594ba283e4d4f94d8cfb81d73ed65114 \
|
||||
--hash=sha256:2e8fdd625e9aba31228e7ddbc36bad5c38dc3ee99a86aa420f89a290bd987ce9 \
|
||||
--hash=sha256:2f3bc2f49b67b1bea82b942d25bc958d4f4ea6709b411cb2b6b9718adf7914ce \
|
||||
--hash=sha256:35d24be9d04d50da3a6f4d61de028c1dd087045385a0ff374d93ef85af61b584 \
|
||||
--hash=sha256:35dbe4e8c73003dff40dfaeb15902910a4360699375e7b47d3c909a83ff27cd0 \
|
||||
--hash=sha256:3dfce831b824ab5cf446ed0c350b793ac6fa5fe33b984305cb4c966a86a8fb79 \
|
||||
--hash=sha256:3f7866365df5a36a7b8de8056cd1c605648f56f9a226d918ed84c85d25e8d55f \
|
||||
--hash=sha256:455cc8c01de3bac6f9c223967cea41f4449f58b4c2e724ec8177382ddd183ab4 \
|
||||
--hash=sha256:4bb937e998be9d5e345f486693e477ba79e4344674484001a0b646be1d530487 \
|
||||
--hash=sha256:52303a20902ca0888dfb83230ca3ee6fbe63c0ad1dd60aa0bba7958ccff454d8 \
|
||||
--hash=sha256:6e0a897d4e09859cc80c6a16a29697406ead752292ace17f1805126a4f63c838 \
|
||||
--hash=sha256:6e1816e7c10966330d77af45f77501f9a68818c065dec0ad11d22b50a0e212e7 \
|
||||
--hash=sha256:73b5921c5c6ce3358c836461b5470bf675601c96d5e5d8f2a446951470614f67 \
|
||||
--hash=sha256:8093cd45cdb5f6c8591cfd1af03d32b32965b0f79b94684cd0c9afdf841982bb \
|
||||
--hash=sha256:864b4a94b60db301899cf373579fd9ef92edddbf0fb2cd5ae99f53ef423ccc56 \
|
||||
--hash=sha256:8a27b4d3ea9c6d086ce8e7cdb3e8d319b6752e2a03238a388ccc83ccbe165f50 \
|
||||
--hash=sha256:91b847969d4784abd855165a2d163f72ac1e58e6dce09a5e46c20e58f19cc96d \
|
||||
--hash=sha256:b47b1028be4758c3167e474884ccc079b94835f058984b15c145966c4df64d27 \
|
||||
--hash=sha256:b68814a322835d8ad671b7acc23a3b2acecba527bb14f4b53fc925f8a27e44d8 \
|
||||
--hash=sha256:bcb50a032c3b6ec7fb281b3a83d2b31ab5246c5b119588725b1350d3a1d9f6a3 \
|
||||
--hash=sha256:c56db7d10b25ce8918b6aec6b08ac401842b47e6c136773bfb3b590753f7fb67 \
|
||||
--hash=sha256:c94b77a13d4f47883e4f97f9fa00f5feadd38af3e6b3c7be45cfdb0a14c7149b \
|
||||
--hash=sha256:db381f6fdaef483ad435f778086ccc4890120aff8df2ba5cfeeac24d280b3145 \
|
||||
--hash=sha256:e6487d01c8b7ed86af30ea141fcc4f93f8a7dde26f94177c1ad637c353bd5c07 \
|
||||
--hash=sha256:e86923fa728dfba39c5bb6046a450bd4eec8ad949ac404eca728cfce320d1732 \
|
||||
--hash=sha256:f6ca36dc1e9eeb46d779869c60001b3065fb670b5775c51421c099ea2a77c3c9 \
|
||||
--hash=sha256:fb62f2cbe790a50d95593fb40e8cca261c31a2f5637455ea39440d6457c2ba25
|
||||
zope.proxy==4.3.3 \
|
||||
--hash=sha256:04646ac04ffa9c8e32fb2b5c3cd42995b2548ea14251f3c21ca704afae88e42c \
|
||||
--hash=sha256:07b6bceea232559d24358832f1cd2ed344bbf05ca83855a5b9698b5f23c5ed60 \
|
||||
--hash=sha256:1ef452cc02e0e2f8e3c917b1a5b936ef3280f2c2ca854ee70ac2164d1655f7e6 \
|
||||
--hash=sha256:22bf61857c5977f34d4e391476d40f9a3b8c6ab24fb0cac448d42d8f8b9bf7b2 \
|
||||
--hash=sha256:299870e3428cbff1cd9f9b34144e76ecdc1d9e3192a8cf5f1b0258f47a239f58 \
|
||||
--hash=sha256:2bfc36bfccbe047671170ea5677efd3d5ab730a55d7e45611d76d495e5b96766 \
|
||||
--hash=sha256:32e82d5a640febc688c0789e15ea875bf696a10cf358f049e1ed841f01710a9b \
|
||||
--hash=sha256:3b2051bdc4bc3f02fa52483f6381cf40d4d48167645241993f9d7ebbd142ed9b \
|
||||
--hash=sha256:3f734bd8a08f5185a64fb6abb8f14dc97ec27a689ca808fb7a83cdd38d745e4f \
|
||||
--hash=sha256:3f78dd8de3112df8bbd970f0916ac876dc3fbe63810bd1cf7cc5eec4cbac4f04 \
|
||||
--hash=sha256:4eabeb48508953ba1f3590ad0773b8daea9e104eec66d661917e9bbcd7125a67 \
|
||||
--hash=sha256:4f05ecc33808187f430f249cb1ccab35c38f570b181f2d380fbe253da94b18d8 \
|
||||
--hash=sha256:4f4f4cbf23d3afc1526294a31e7b3eaa0f682cc28ac5366065dc1d6bb18bd7be \
|
||||
--hash=sha256:5483d5e70aacd06f0aa3effec9fed597c0b50f45060956eeeb1203c44d4338c3 \
|
||||
--hash=sha256:56a5f9b46892b115a75d0a1f2292431ad5988461175826600acc69a24cb3edee \
|
||||
--hash=sha256:64bb63af8a06f736927d260efdd4dfc5253d42244f281a8063e4b9eea2ddcbc5 \
|
||||
--hash=sha256:653f8cbefcf7c6ac4cece2cdef367c4faa2b7c19795d52bd7cbec11a8739a7c1 \
|
||||
--hash=sha256:664211d63306e4bd4eec35bf2b4bd9db61c394037911cf2d1804c43b511a49f1 \
|
||||
--hash=sha256:6651e6caed66a8fff0fef1a3e81c0ed2253bf361c0fdc834500488732c5d16e9 \
|
||||
--hash=sha256:6c1fba6cdfdf105739d3069cf7b07664f2944d82a8098218ab2300a82d8f40fc \
|
||||
--hash=sha256:6e64246e6e9044a4534a69dca1283c6ddab6e757be5e6874f69024329b3aa61f \
|
||||
--hash=sha256:838390245c7ec137af4993c0c8052f49d5ec79e422b4451bfa37fee9b9ccaa01 \
|
||||
--hash=sha256:856b410a14793069d8ba35f33fff667213ea66f2df25a0024cc72a7493c56d4c \
|
||||
--hash=sha256:8b932c364c1d1605a91907a41128ed0ee8a2d326fc0fafb2c55cd46f545f4599 \
|
||||
--hash=sha256:9086cf6d20f08dae7f296a78f6c77d1f8d24079d448f023ee0eb329078dd35e1 \
|
||||
--hash=sha256:9698533c14afa0548188de4968a7932d1f3f965f3f5ba1474de673596bb875af \
|
||||
--hash=sha256:9b12b05dd7c28f5068387c1afee8cb94f9d02501e7ef495a7c5c7e27139b96ad \
|
||||
--hash=sha256:a884c7426a5bc6fb7fc71a55ad14e66818e13f05b78b20a6f37175f324b7acb8 \
|
||||
--hash=sha256:abe9e7f1a3e76286c5f5baf2bf5162d41dc0310da493b34a2c36555f38d928f7 \
|
||||
--hash=sha256:bd6fde63b015a27262be06bd6bbdd895273cc2bdf2d4c7e1c83711d26a8fbace \
|
||||
--hash=sha256:bda7c62c954f47b87ed9a89f525eee1b318ec7c2162dfdba76c2ccfa334e0caa \
|
||||
--hash=sha256:be8a4908dd3f6e965993c0068b006bdbd0474fbcbd1da4893b49356e73fc1557 \
|
||||
--hash=sha256:ced65fc3c7d7205267506d854bb1815bb445899cca9d21d1d4b949070a635546 \
|
||||
--hash=sha256:dac4279aa05055d3897ab5e5ee5a7b39db121f91df65a530f8b1ac7f9bd93119 \
|
||||
--hash=sha256:e4f1863056e3e4f399c285b67fa816f411a7bfa1c81ef50e186126164e396e59 \
|
||||
--hash=sha256:ecd85f68b8cd9ab78a0141e87ea9a53b2f31fd9b1350a1c44da1f7481b5363ef \
|
||||
--hash=sha256:ed269b83750413e8fc5c96276372f49ee3fcb7ed61c49fe8e5a67f54459a5a4a \
|
||||
--hash=sha256:f19b0b80cba73b204dee68501870b11067711d21d243fb6774256d3ca2e5391f \
|
||||
--hash=sha256:ffdafb98db7574f9da84c489a10a5d582079a888cb43c64e9e6b0e3fe1034685
|
||||
zope.hookable==5.0.1 \
|
||||
--hash=sha256:0194b9b9e7f614abba60c90b231908861036578297515d3d6508eb10190f266d \
|
||||
--hash=sha256:0c2977473918bdefc6fa8dfb311f154e7f13c6133957fe649704deca79b92093 \
|
||||
--hash=sha256:17b8bdb3b77e03a152ca0d5ca185a7ae0156f5e5a2dbddf538676633a1f7380f \
|
||||
--hash=sha256:29d07681a78042cdd15b268ae9decffed9ace68a53eebeb61d65ae931d158841 \
|
||||
--hash=sha256:36fb1b35d1150267cb0543a1ddd950c0bc2c75ed0e6e92e3aaa6ac2e29416cb7 \
|
||||
--hash=sha256:3aed60c2bb5e812bbf9295c70f25b17ac37c233f30447a96c67913ba5073642f \
|
||||
--hash=sha256:3cac1565cc768911e72ca9ec4ddf5c5109e1fef0104f19f06649cf1874943b60 \
|
||||
--hash=sha256:3d4bc0cc4a37c3cd3081063142eeb2125511db3c13f6dc932d899c512690378e \
|
||||
--hash=sha256:3f73096f27b8c28be53ffb6604f7b570fbbb82f273c6febe5f58119009b59898 \
|
||||
--hash=sha256:522d1153d93f2d48aa0bd9fb778d8d4500be2e4dcf86c3150768f0e3adbbc4ef \
|
||||
--hash=sha256:523d2928fb7377bbdbc9af9c0b14ad73e6eaf226349f105733bdae27efd15b5a \
|
||||
--hash=sha256:5848309d4fc5c02150a45e8f8d2227e5bfda386a508bbd3160fed7c633c5a2fa \
|
||||
--hash=sha256:6781f86e6d54a110980a76e761eb54590630fd2af2a17d7edf02a079d2646c1d \
|
||||
--hash=sha256:6fd27921ebf3aaa945fa25d790f1f2046204f24dba4946f82f5f0a442577c3e9 \
|
||||
--hash=sha256:70d581862863f6bf9e175e85c9d70c2d7155f53fb04dcdb2f73cf288ca559a53 \
|
||||
--hash=sha256:81867c23b0dc66c8366f351d00923f2bc5902820a24c2534dfd7bf01a5879963 \
|
||||
--hash=sha256:81db29edadcbb740cd2716c95a297893a546ed89db1bfe9110168732d7f0afdd \
|
||||
--hash=sha256:86bd12624068cea60860a0759af5e2c3adc89c12aef6f71cf12f577e28deefe3 \
|
||||
--hash=sha256:9c184d8f9f7a76e1ced99855ccf390ffdd0ec3765e5cbf7b9cada600accc0a1e \
|
||||
--hash=sha256:acc789e8c29c13555e43fe4bf9fcd15a65512c9645e97bbaa5602e3201252b02 \
|
||||
--hash=sha256:afaa740206b7660d4cc3b8f120426c85761f51379af7a5b05451f624ad12b0af \
|
||||
--hash=sha256:b5f5fa323f878bb16eae68ea1ba7f6c0419d4695d0248bed4b18f51d7ce5ab85 \
|
||||
--hash=sha256:bd89e0e2c67bf4ac3aca2a19702b1a37269fb1923827f68324ac2e7afd6e3406 \
|
||||
--hash=sha256:c212de743283ec0735db24ec6ad913758df3af1b7217550ff270038062afd6ae \
|
||||
--hash=sha256:ca553f524293a0bdea05e7f44c3e685e4b7b022cb37d87bc4a3efa0f86587a8d \
|
||||
--hash=sha256:cab67065a3db92f636128d3157cc5424a145f82d96fb47159c539132833a6d36 \
|
||||
--hash=sha256:d3b3b3eedfdbf6b02898216e85aa6baf50207f4378a2a6803d6d47650cd37031 \
|
||||
--hash=sha256:d9f4a5a72f40256b686d31c5c0b1fde503172307beb12c1568296e76118e402c \
|
||||
--hash=sha256:df5067d87aaa111ed5d050e1ee853ba284969497f91806efd42425f5348f1c06 \
|
||||
--hash=sha256:e2587644812c6138f05b8a41594a8337c6790e3baf9a01915e52438c13fc6bef \
|
||||
--hash=sha256:e27fd877662db94f897f3fd532ef211ca4901eb1a70ba456f15c0866a985464a \
|
||||
--hash=sha256:e427ebbdd223c72e06ba94c004bb04e996c84dec8a0fa84e837556ae145c439e \
|
||||
--hash=sha256:e583ad4309c203ef75a09d43434cf9c2b4fa247997ecb0dcad769982c39411c7 \
|
||||
--hash=sha256:e760b2bc8ece9200804f0c2b64d10147ecaf18455a2a90827fbec4c9d84f3ad5 \
|
||||
--hash=sha256:ea9a9cc8bcc70e18023f30fa2f53d11ae069572a162791224e60cd65df55fb69 \
|
||||
--hash=sha256:ecb3f17dce4803c1099bd21742cd126b59817a4e76a6544d31d2cca6e30dbffd \
|
||||
--hash=sha256:ed794e3b3de42486d30444fb60b5561e724ee8a2d1b17b0c2e0f81e3ddaf7a87 \
|
||||
--hash=sha256:ee885d347279e38226d0a437b6a932f207f691c502ee565aba27a7022f1285df \
|
||||
--hash=sha256:fd5e7bc5f24f7e3d490698f7b854659a9851da2187414617cd5ed360af7efd63 \
|
||||
--hash=sha256:fe45f6870f7588ac7b2763ff1ce98cce59369717afe70cc353ec5218bc854bcc
|
||||
zope.interface==5.1.0 \
|
||||
--hash=sha256:0103cba5ed09f27d2e3de7e48bb320338592e2fabc5ce1432cf33808eb2dfd8b \
|
||||
--hash=sha256:14415d6979356629f1c386c8c4249b4d0082f2ea7f75871ebad2e29584bd16c5 \
|
||||
--hash=sha256:1ae4693ccee94c6e0c88a4568fb3b34af8871c60f5ba30cf9f94977ed0e53ddd \
|
||||
--hash=sha256:1b87ed2dc05cb835138f6a6e3595593fea3564d712cb2eb2de963a41fd35758c \
|
||||
--hash=sha256:269b27f60bcf45438e8683269f8ecd1235fa13e5411de93dae3b9ee4fe7f7bc7 \
|
||||
--hash=sha256:27d287e61639d692563d9dab76bafe071fbeb26818dd6a32a0022f3f7ca884b5 \
|
||||
--hash=sha256:39106649c3082972106f930766ae23d1464a73b7d30b3698c986f74bf1256a34 \
|
||||
--hash=sha256:40e4c42bd27ed3c11b2c983fecfb03356fae1209de10686d03c02c8696a1d90e \
|
||||
--hash=sha256:461d4339b3b8f3335d7e2c90ce335eb275488c587b61aca4b305196dde2ff086 \
|
||||
--hash=sha256:4f98f70328bc788c86a6a1a8a14b0ea979f81ae6015dd6c72978f1feff70ecda \
|
||||
--hash=sha256:558a20a0845d1a5dc6ff87cd0f63d7dac982d7c3be05d2ffb6322a87c17fa286 \
|
||||
--hash=sha256:562dccd37acec149458c1791da459f130c6cf8902c94c93b8d47c6337b9fb826 \
|
||||
--hash=sha256:5e86c66a6dea8ab6152e83b0facc856dc4d435fe0f872f01d66ce0a2131b7f1d \
|
||||
--hash=sha256:60a207efcd8c11d6bbeb7862e33418fba4e4ad79846d88d160d7231fcb42a5ee \
|
||||
--hash=sha256:645a7092b77fdbc3f68d3cc98f9d3e71510e419f54019d6e282328c0dd140dcd \
|
||||
--hash=sha256:6874367586c020705a44eecdad5d6b587c64b892e34305bb6ed87c9bbe22a5e9 \
|
||||
--hash=sha256:74bf0a4f9091131de09286f9a605db449840e313753949fe07c8d0fe7659ad1e \
|
||||
--hash=sha256:7b726194f938791a6691c7592c8b9e805fc6d1b9632a833b9c0640828cd49cbc \
|
||||
--hash=sha256:8149ded7f90154fdc1a40e0c8975df58041a6f693b8f7edcd9348484e9dc17fe \
|
||||
--hash=sha256:8cccf7057c7d19064a9e27660f5aec4e5c4001ffcf653a47531bde19b5aa2a8a \
|
||||
--hash=sha256:911714b08b63d155f9c948da2b5534b223a1a4fc50bb67139ab68b277c938578 \
|
||||
--hash=sha256:a5f8f85986197d1dd6444763c4a15c991bfed86d835a1f6f7d476f7198d5f56a \
|
||||
--hash=sha256:a744132d0abaa854d1aad50ba9bc64e79c6f835b3e92521db4235a1991176813 \
|
||||
--hash=sha256:af2c14efc0bb0e91af63d00080ccc067866fb8cbbaca2b0438ab4105f5e0f08d \
|
||||
--hash=sha256:b054eb0a8aa712c8e9030065a59b5e6a5cf0746ecdb5f087cca5ec7685690c19 \
|
||||
--hash=sha256:b0becb75418f8a130e9d465e718316cd17c7a8acce6fe8fe07adc72762bee425 \
|
||||
--hash=sha256:b1d2ed1cbda2ae107283befd9284e650d840f8f7568cb9060b5466d25dc48975 \
|
||||
--hash=sha256:ba4261c8ad00b49d48bbb3b5af388bb7576edfc0ca50a49c11dcb77caa1d897e \
|
||||
--hash=sha256:d1fe9d7d09bb07228650903d6a9dc48ea649e3b8c69b1d263419cc722b3938e8 \
|
||||
--hash=sha256:d7804f6a71fc2dda888ef2de266727ec2f3915373d5a785ed4ddc603bbc91e08 \
|
||||
--hash=sha256:da2844fba024dd58eaa712561da47dcd1e7ad544a257482392472eae1c86d5e5 \
|
||||
--hash=sha256:dcefc97d1daf8d55199420e9162ab584ed0893a109f45e438b9794ced44c9fd0 \
|
||||
--hash=sha256:dd98c436a1fc56f48c70882cc243df89ad036210d871c7427dc164b31500dc11 \
|
||||
--hash=sha256:e74671e43ed4569fbd7989e5eecc7d06dc134b571872ab1d5a88f4a123814e9f \
|
||||
--hash=sha256:eb9b92f456ff3ec746cd4935b73c1117538d6124b8617bc0fe6fda0b3816e345 \
|
||||
--hash=sha256:ebb4e637a1fb861c34e48a00d03cffa9234f42bef923aec44e5625ffb9a8e8f9 \
|
||||
--hash=sha256:ef739fe89e7f43fb6494a43b1878a36273e5924869ba1d866f752c5812ae8d58 \
|
||||
--hash=sha256:f40db0e02a8157d2b90857c24d89b6310f9b6c3642369852cdc3b5ac49b92afc \
|
||||
--hash=sha256:f68bf937f113b88c866d090fea0bc52a098695173fc613b055a17ff0cf9683b6 \
|
||||
--hash=sha256:fb55c182a3f7b84c1a2d6de5fa7b1a05d4660d866b91dbf8d74549c57a1499e8
|
||||
zope.proxy==4.3.5 \
|
||||
--hash=sha256:00573dfa755d0703ab84bb23cb6ecf97bb683c34b340d4df76651f97b0bab068 \
|
||||
--hash=sha256:092049280f2848d2ba1b57b71fe04881762a220a97b65288bcb0968bb199ec30 \
|
||||
--hash=sha256:0cbd27b4d3718b5ec74fc65ffa53c78d34c65c6fd9411b8352d2a4f855220cf1 \
|
||||
--hash=sha256:17fc7e16d0c81f833a138818a30f366696653d521febc8e892858041c4d88785 \
|
||||
--hash=sha256:19577dfeb70e8a67249ba92c8ad20589a1a2d86a8d693647fa8385408a4c17b0 \
|
||||
--hash=sha256:207aa914576b1181597a1516e1b90599dc690c095343ae281b0772e44945e6a4 \
|
||||
--hash=sha256:219a7db5ed53e523eb4a4769f13105118b6d5b04ed169a283c9775af221e231f \
|
||||
--hash=sha256:2b50ea79849e46b5f4f2b0247a3687505d32d161eeb16a75f6f7e6cd81936e43 \
|
||||
--hash=sha256:5903d38362b6c716e66bbe470f190579c530a5baf03dbc8500e5c2357aa569a5 \
|
||||
--hash=sha256:5c24903675e271bd688c6e9e7df5775ac6b168feb87dbe0e4bcc90805f21b28f \
|
||||
--hash=sha256:5ef6bc5ed98139e084f4e91100f2b098a0cd3493d4e76f9d6b3f7b95d7ad0f06 \
|
||||
--hash=sha256:61b55ae3c23a126a788b33ffb18f37d6668e79a05e756588d9e4d4be7246ab1c \
|
||||
--hash=sha256:63ddb992931a5e616c87d3d89f5a58db086e617548005c7f9059fac68c03a5cc \
|
||||
--hash=sha256:6943da9c09870490dcfd50c4909c0cc19f434fa6948f61282dc9cb07bcf08160 \
|
||||
--hash=sha256:6ad40f85c1207803d581d5d75e9ea25327cd524925699a83dfc03bf8e4ba72b7 \
|
||||
--hash=sha256:6b44433a79bdd7af0e3337bd7bbcf53dd1f9b0fa66bf21bcb756060ce32a96c1 \
|
||||
--hash=sha256:6bbaa245015d933a4172395baad7874373f162955d73612f0b66b6c2c33b6366 \
|
||||
--hash=sha256:7007227f4ea85b40a2f5e5a244479f6a6dfcf906db9b55e812a814a8f0e2c28d \
|
||||
--hash=sha256:74884a0aec1f1609190ec8b34b5d58fb3b5353cf22b96161e13e0e835f13518f \
|
||||
--hash=sha256:7d25fe5571ddb16369054f54cdd883f23de9941476d97f2b92eb6d7d83afe22d \
|
||||
--hash=sha256:7e162bdc5e3baad26b2262240be7d2bab36991d85a6a556e48b9dfb402370261 \
|
||||
--hash=sha256:814d62678dc3a30f4aa081982d830b7c342cf230ffc9d030b020cb154eeebf9e \
|
||||
--hash=sha256:8878a34c5313ee52e20aa50b03138af8d472bae465710fb954d133a9bfd3c38d \
|
||||
--hash=sha256:a66a0d94e5b081d5d695e66d6667e91e74d79e273eee95c1747717ba9cb70792 \
|
||||
--hash=sha256:a69f5cbf4addcfdf03dda564a671040127a6b7c34cf9fe4973582e68441b63fa \
|
||||
--hash=sha256:b00f9f0c334d07709d3f73a7cb8ae63c6ca1a90c790a63b5e7effa666ef96021 \
|
||||
--hash=sha256:b6ed71e4a7b4690447b626f499d978aa13197a0e592950e5d7020308f6054698 \
|
||||
--hash=sha256:bdf5041e5851526e885af579d2f455348dba68d74f14a32781933569a327fddf \
|
||||
--hash=sha256:be034360dd34e62608419f86e799c97d389c10a0e677a25f236a971b2f40dac9 \
|
||||
--hash=sha256:cc8f590a5eed30b314ae6b0232d925519ade433f663de79cc3783e4b10d662ba \
|
||||
--hash=sha256:cd7a318a15fe6cc4584bf3c4426f092ed08c0fd012cf2a9173114234fe193e11 \
|
||||
--hash=sha256:cf19b5f63a59c20306e034e691402b02055c8f4e38bf6792c23cad489162a642 \
|
||||
--hash=sha256:cfc781ce442ec407c841e9aa51d0e1024f72b6ec34caa8fdb6ef9576d549acf2 \
|
||||
--hash=sha256:dea9f6f8633571e18bc20cad83603072e697103a567f4b0738d52dd0211b4527 \
|
||||
--hash=sha256:e4a86a1d5eb2cce83c5972b3930c7c1eac81ab3508464345e2b8e54f119d5505 \
|
||||
--hash=sha256:e7106374d4a74ed9ff00c46cc00f0a9f06a0775f8868e423f85d4464d2333679 \
|
||||
--hash=sha256:e98a8a585b5668aa9e34d10f7785abf9545fe72663b4bfc16c99a115185ae6a5 \
|
||||
--hash=sha256:f64840e68483316eb58d82c376ad3585ca995e69e33b230436de0cdddf7363f9 \
|
||||
--hash=sha256:f8f4b0a9e6683e43889852130595c8854d8ae237f2324a053cdd884de936aa9b \
|
||||
--hash=sha256:fc45a53219ed30a7f670a6d8c98527af0020e6fd4ee4c0a8fb59f147f06d816c
|
||||
|
||||
# Contains the requirements for the letsencrypt package.
|
||||
#
|
||||
@@ -1533,18 +1530,18 @@ letsencrypt==0.7.0 \
|
||||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==1.5.0 \
|
||||
--hash=sha256:ec1f01af06b52a6f079f5b02cb70e88f0671a7b13ecb3e45b040563e32c6e53a \
|
||||
--hash=sha256:c52017a4f84137e1312c898d6ae69c5f7977d79d2bd4c2df013cbbf39b6539bf
|
||||
acme==1.5.0 \
|
||||
--hash=sha256:66de67b394bb7606f97f2c21507e6eb6a88936db2a940f5c4893025f87e3852a \
|
||||
--hash=sha256:b051ff7dd3935b2032c2f8c8386e905d9b658eba9f3455e352650d85bea9c8f0
|
||||
certbot-apache==1.5.0 \
|
||||
--hash=sha256:d2c28be6dcd6c56a8040c8c733e72c1341238b1b47fb59f544eb832b9d5c81ba \
|
||||
--hash=sha256:3eec5a49ae4fcf86213f962eb1e11d8a725b65e7dcee18f9b92c7aa73f821764
|
||||
certbot-nginx==1.5.0 \
|
||||
--hash=sha256:3d27fd02ebe15b07ce5fa9525ceeda82aa5fdc45aa064729434faff0442d1f91 \
|
||||
--hash=sha256:b38f101588af6d2b8ea7c2e3334f249afbe14461a85add2f1420091d860df983
|
||||
certbot==1.6.0 \
|
||||
--hash=sha256:7237ac851ef7f3ff2d5ddb49e692e4bd5346273734cbc531531e4ad56d14d460 \
|
||||
--hash=sha256:d373ee0f24ab06f561efa2b00f68cff43521b003d87fbf4d9e869e7cc7395481
|
||||
acme==1.6.0 \
|
||||
--hash=sha256:dc532fee475dde07a843232f69f54b185ba23af6cce9d2e1a1dc132ce2e34f64 \
|
||||
--hash=sha256:fe76e06ae1e9b12304f9e9691ff901da6d2fd588fea2765f891b8cd15d6b3f2b
|
||||
certbot-apache==1.6.0 \
|
||||
--hash=sha256:d6080664fe24fc5dc1e519382ebe5a5215f3b886ceaa335336a1db2c1b1ed95e \
|
||||
--hash=sha256:e0232a1f1c5513701de06bccb88b57b7d76d9db28c6559fba8539f88293c85ea
|
||||
certbot-nginx==1.6.0 \
|
||||
--hash=sha256:6ef97185d9c07ea97656e7b439e7ccfa8e5090f6802e9162e8f5a79080bc5a76 \
|
||||
--hash=sha256:facc59e066d7e5623fbc068fe2fcc5e1f802c2441d148e37ff96ad90b893600a
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@@ -9,6 +9,8 @@ import shutil
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from cryptography.x509 import NameOID
|
||||
|
||||
import pytest
|
||||
|
||||
from certbot_integration_tests.certbot_tests import context as certbot_context
|
||||
@@ -628,3 +630,31 @@ def test_dry_run_deactivate_authzs(context):
|
||||
context.certbot(args)
|
||||
with open(join(context.workspace, 'logs', 'letsencrypt.log'), 'r') as f:
|
||||
assert log_line in f.read(), 'Second order should have been recreated due to authz reuse'
|
||||
|
||||
|
||||
def test_preferred_chain(context):
|
||||
"""Test that --preferred-chain results in the correct chain.pem being produced"""
|
||||
try:
|
||||
issuers = misc.get_acme_issuers(context)
|
||||
except NotImplementedError:
|
||||
pytest.skip('This ACME server does not support alternative issuers.')
|
||||
|
||||
names = [i.issuer.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value \
|
||||
for i in issuers]
|
||||
|
||||
domain = context.get_domain('preferred-chain')
|
||||
cert_path = join(context.config_dir, 'live', domain, 'chain.pem')
|
||||
conf_path = join(context.config_dir, 'renewal', '{}.conf'.format(domain))
|
||||
|
||||
for (requested, expected) in [(n, n) for n in names] + [('nonexistent', names[0])]:
|
||||
args = ['certonly', '--cert-name', domain, '-d', domain,
|
||||
'--preferred-chain', requested, '--force-renewal']
|
||||
context.certbot(args)
|
||||
|
||||
dumped = misc.read_certificate(cert_path)
|
||||
assert 'Issuer: CN={}'.format(expected) in dumped, \
|
||||
'Expected chain issuer to be {} when preferring {}'.format(expected, requested)
|
||||
|
||||
with open(conf_path, 'r') as f:
|
||||
assert 'preferred_chain = {}'.format(requested) in f.read(), \
|
||||
'Expected preferred_chain to be set in renewal config'
|
||||
@@ -130,6 +130,7 @@ class ACMEServer(object):
|
||||
environ['PEBBLE_VA_NOSLEEP'] = '1'
|
||||
environ['PEBBLE_WFE_NONCEREJECT'] = '0'
|
||||
environ['PEBBLE_AUTHZREUSE'] = '100'
|
||||
environ['PEBBLE_ALTERNATE_ROOTS'] = str(PEBBLE_ALTERNATE_ROOTS)
|
||||
|
||||
self._launch_process(
|
||||
[pebble_path, '-config', pebble_config_path, '-dnsserver', '127.0.0.1:8053', '-strict'],
|
||||
|
||||
@@ -7,3 +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
|
||||
@@ -19,16 +19,30 @@ from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives.serialization import Encoding
|
||||
from cryptography.hazmat.primitives.serialization import NoEncryption
|
||||
from cryptography.hazmat.primitives.serialization import PrivateFormat
|
||||
from cryptography.x509 import load_pem_x509_certificate
|
||||
from OpenSSL import crypto
|
||||
import pkg_resources
|
||||
import requests
|
||||
from six.moves import SimpleHTTPServer
|
||||
from six.moves import socketserver
|
||||
|
||||
from certbot_integration_tests.utils.constants import \
|
||||
PEBBLE_ALTERNATE_ROOTS, PEBBLE_MANAGEMENT_URL
|
||||
|
||||
RSA_KEY_TYPE = 'rsa'
|
||||
ECDSA_KEY_TYPE = 'ecdsa'
|
||||
|
||||
|
||||
def _suppress_x509_verification_warnings():
|
||||
try:
|
||||
import urllib3
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
except ImportError:
|
||||
# Handle old versions of request with vendorized urllib3
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
|
||||
def check_until_timeout(url, attempts=30):
|
||||
"""
|
||||
Wait and block until given url responds with status 200, or raise an exception
|
||||
@@ -37,14 +51,7 @@ def check_until_timeout(url, attempts=30):
|
||||
:param int attempts: the number of times to try to connect to the URL
|
||||
:raise ValueError: exception raised if unable to reach the URL
|
||||
"""
|
||||
try:
|
||||
import urllib3
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
except ImportError:
|
||||
# Handle old versions of request with vendorized urllib3
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
_suppress_x509_verification_warnings()
|
||||
for _ in range(attempts):
|
||||
time.sleep(1)
|
||||
try:
|
||||
@@ -299,3 +306,23 @@ def echo(keyword, path=None):
|
||||
.format(keyword))
|
||||
return '{0} -c "from __future__ import print_function; print(\'{1}\')"{2}'.format(
|
||||
os.path.basename(sys.executable), keyword, ' >> "{0}"'.format(path) if path else '')
|
||||
|
||||
|
||||
def get_acme_issuers(context):
|
||||
"""Gets the list of one or more issuer certificates from the ACME server used by the
|
||||
context.
|
||||
:param context: the testing context.
|
||||
:return: the `list of x509.Certificate` representing the list of issuers.
|
||||
"""
|
||||
# TODO: in fact, Boulder has alternate chains in config-next/, just not yet in config/.
|
||||
if context.acme_server != "pebble":
|
||||
raise NotImplementedError()
|
||||
|
||||
_suppress_x509_verification_warnings()
|
||||
|
||||
issuers = []
|
||||
for i in range(PEBBLE_ALTERNATE_ROOTS + 1):
|
||||
request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediates/{}'.format(i), verify=False)
|
||||
issuers.append(load_pem_x509_certificate(request.content, default_backend()))
|
||||
|
||||
return issuers
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -26,7 +26,7 @@ install_requires = [
|
||||
# However environment markers are supported only with setuptools >= 36.2.
|
||||
# So this dependency is not added for old Linux distributions with old setuptools,
|
||||
# in order to allow these systems to build certbot from sources.
|
||||
if StrictVersion(setuptools_version) >= StrictVersion('36.2'):
|
||||
if LooseVersion(setuptools_version) >= LooseVersion('36.2'):
|
||||
install_requires.append("pywin32>=224 ; sys_platform == 'win32'")
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Error, you are trying to build certbot wheels using an old version '
|
||||
|
||||
0
certbot-ci/snap_integration_tests/__init__.py
Normal file
0
certbot-ci/snap_integration_tests/__init__.py
Normal file
40
certbot-ci/snap_integration_tests/conftest.py
Normal file
40
certbot-ci/snap_integration_tests/conftest.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
General conftest for pytest execution of all integration tests lying
|
||||
in the snap_installer_integration tests package.
|
||||
As stated by pytest documentation, conftest module is used to set on
|
||||
for a directory a specific configuration using built-in pytest hooks.
|
||||
|
||||
See https://docs.pytest.org/en/latest/reference.html#hook-reference
|
||||
"""
|
||||
import glob
|
||||
import os
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
"""
|
||||
Standard pytest hook to add options to the pytest parser.
|
||||
:param parser: current pytest parser that will be used on the CLI
|
||||
"""
|
||||
parser.addoption('--snap-folder', required=True,
|
||||
help='set the folder path where snaps to test are located')
|
||||
parser.addoption('--allow-persistent-changes', action='store_true',
|
||||
help='needs to be set, and confirm that the test will make persistent changes on this machine')
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
"""
|
||||
Standard pytest hook used to add a configuration logic for each node of a pytest run.
|
||||
:param config: the current pytest configuration
|
||||
"""
|
||||
if not config.option.allow_persistent_changes:
|
||||
raise RuntimeError('This integration test would install the Certbot snap on your machine. '
|
||||
'Please run it again with the `--allow-persistent-changes` flag set to acknowledge.')
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
"""
|
||||
Generate (multiple) parametrized calls to a test function.
|
||||
"""
|
||||
if "dns_snap_path" in metafunc.fixturenames:
|
||||
snap_dns_path_list = glob.glob(os.path.join(metafunc.config.getoption('snap_folder'), 'certbot-dns-*_*.snap'))
|
||||
metafunc.parametrize("dns_snap_path", snap_dns_path_list)
|
||||
42
certbot-ci/snap_integration_tests/dns_tests/test_main.py
Normal file
42
certbot-ci/snap_integration_tests/dns_tests/test_main.py
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
import pytest
|
||||
import subprocess
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def install_certbot_snap(request):
|
||||
with pytest.raises(Exception):
|
||||
subprocess.check_call(['certbot', '--version'])
|
||||
try:
|
||||
snap_path = glob.glob(os.path.join(request.config.getoption("snap_folder"),
|
||||
'certbot_*.snap'))[0]
|
||||
subprocess.check_call(['snap', 'install', '--classic', '--dangerous', snap_path])
|
||||
subprocess.check_call(['certbot', '--version'])
|
||||
yield
|
||||
finally:
|
||||
subprocess.call(['snap', 'remove', 'certbot'])
|
||||
|
||||
|
||||
def test_dns_plugin_install(dns_snap_path):
|
||||
"""
|
||||
Test that each DNS plugin Certbot snap can be installed
|
||||
and is usable with the Certbot snap.
|
||||
"""
|
||||
plugin_name = re.match(r'^certbot-(dns-\w+)_.*\.snap$',
|
||||
os.path.basename(dns_snap_path)).group(1)
|
||||
snap_name = 'certbot-{0}'.format(plugin_name)
|
||||
assert plugin_name not in subprocess.check_output(['certbot', 'plugins', '--prepare'],
|
||||
universal_newlines=True)
|
||||
|
||||
try:
|
||||
subprocess.check_call(['snap', 'install', '--dangerous', dns_snap_path])
|
||||
subprocess.check_call(['snap', 'set', 'certbot', 'trust-plugin-with-root=ok'])
|
||||
subprocess.check_call(['snap', 'connect', 'certbot:plugin', snap_name])
|
||||
|
||||
assert plugin_name in subprocess.check_output(['certbot', 'plugins', '--prepare'],
|
||||
universal_newlines=True)
|
||||
finally:
|
||||
subprocess.call(['snap', 'remove', 'plugin_name'])
|
||||
@@ -1,11 +1,11 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'certbot',
|
||||
@@ -15,7 +15,7 @@ install_requires = [
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
@@ -21,8 +21,8 @@ Credentials
|
||||
-----------
|
||||
|
||||
Use of this plugin requires a configuration file containing Cloudflare API
|
||||
credentials, obtained from your Cloudflare
|
||||
`account page <https://dash.cloudflare.com/profile/api-tokens>`_.
|
||||
credentials, obtained from your
|
||||
`Cloudflare dashboard <https://dash.cloudflare.com/?to=/:account/profile/api-tokens>`_.
|
||||
|
||||
Previously, Cloudflare's "Global API Key" was used for authentication, however
|
||||
this key can access the entire Cloudflare API for all domains in your account,
|
||||
@@ -31,11 +31,8 @@ meaning it could cause a lot of damage if leaked.
|
||||
Cloudflare's newer API Tokens can be restricted to specific domains and
|
||||
operations, and are therefore now the recommended authentication option.
|
||||
|
||||
However, due to some shortcomings in Cloudflare's implementation of Tokens,
|
||||
Tokens created for Certbot currently require ``Zone:Zone:Read`` and ``Zone:DNS:Edit``
|
||||
permissions for **all** zones in your account. While this is not ideal, your Token
|
||||
will still have fewer permission than the Global key, so it's still worth doing.
|
||||
Hopefully Cloudflare will improve this in the future.
|
||||
The Token needed by Certbot requires ``Zone:DNS:Edit`` permissions for only the
|
||||
zones you need certificates for.
|
||||
|
||||
Using Cloudflare Tokens also requires at least version 2.3.1 of the ``cloudflare``
|
||||
python module. If the version that automatically installed with this plugin is
|
||||
|
||||
@@ -14,7 +14,7 @@ from certbot.plugins import dns_common
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ACCOUNT_URL = 'https://dash.cloudflare.com/profile/api-tokens'
|
||||
ACCOUNT_URL = 'https://dash.cloudflare.com/?to=/:account/profile/api-tokens'
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||
@@ -118,7 +118,7 @@ class _CloudflareClient(object):
|
||||
code = int(e)
|
||||
hint = None
|
||||
|
||||
if code == 9109:
|
||||
if code == 1009:
|
||||
hint = 'Does your API token have "Zone:DNS:Edit" permissions?'
|
||||
|
||||
logger.error('Encountered CloudFlareAPIError adding TXT record: %d %s', e, e)
|
||||
@@ -210,11 +210,22 @@ class _CloudflareClient(object):
|
||||
logger.debug('Found zone_id of %s for %s using name %s', zone_id, domain, zone_name)
|
||||
return zone_id
|
||||
|
||||
raise errors.PluginError('Unable to determine zone_id for {0} using zone names: {1}. '
|
||||
'Please confirm that the domain name has been entered correctly '
|
||||
'and is already associated with the supplied Cloudflare account.{2}'
|
||||
.format(domain, zone_name_guesses, ' The error from Cloudflare was:'
|
||||
' {0} {1}'.format(code, msg) if code is not None else ''))
|
||||
if msg is not None:
|
||||
if 'com.cloudflare.api.account.zone.list' in msg:
|
||||
raise errors.PluginError('Unable to determine zone_id for {0} using zone names: '
|
||||
'{1}. Please confirm that the domain name has been '
|
||||
'entered correctly and your Cloudflare Token has access '
|
||||
'to the domain.'.format(domain, zone_name_guesses))
|
||||
else:
|
||||
raise errors.PluginError('Unable to determine zone_id for {0} using zone names: '
|
||||
'{1}. The error from Cloudflare was: {2} {3}.'
|
||||
.format(domain, zone_name_guesses, code, msg))
|
||||
else:
|
||||
raise errors.PluginError('Unable to determine zone_id for {0} using zone names: '
|
||||
'{1}. Please confirm that the domain name has been '
|
||||
'entered correctly and is already associated with the '
|
||||
'supplied Cloudflare account.'
|
||||
.format(domain, zone_name_guesses))
|
||||
|
||||
def _find_txt_record_id(self, zone_id, record_name, record_content):
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,19 +7,26 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
'cloudflare>=1.5.1',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-cloudflare/snap/snapcraft.yaml
Normal file
25
certbot-dns-cloudflare/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-cloudflare
|
||||
summary: Cloudflare DNS Authenticator plugin for Certbot
|
||||
description: Cloudflare DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-cloudflare
|
||||
|
||||
parts:
|
||||
certbot-dns-cloudflare:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -133,7 +133,7 @@ class CloudflareClientTest(unittest.TestCase):
|
||||
def test_add_txt_record_error(self):
|
||||
self.cf.zones.get.return_value = [{'id': self.zone_id}]
|
||||
|
||||
self.cf.zones.dns_records.post.side_effect = CloudFlare.exceptions.CloudFlareAPIError(9109, '', '')
|
||||
self.cf.zones.dns_records.post.side_effect = CloudFlare.exceptions.CloudFlareAPIError(1009, '', '')
|
||||
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
@@ -175,6 +175,12 @@ class CloudflareClientTest(unittest.TestCase):
|
||||
self.cloudflare_client.add_txt_record,
|
||||
DOMAIN, self.record_name, self.record_content, self.record_ttl)
|
||||
|
||||
self.cf.zones.get.side_effect = CloudFlare.exceptions.CloudFlareAPIError(0, 'com.cloudflare.api.account.zone.list', '')
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
self.cloudflare_client.add_txt_record,
|
||||
DOMAIN, self.record_name, self.record_content, self.record_ttl)
|
||||
|
||||
def test_del_txt_record(self):
|
||||
self.cf.zones.get.return_value = [{'id': self.zone_id}]
|
||||
self.cf.zones.dns_records.get.return_value = [{'id': self.record_id}]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,19 +7,26 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-cloudxns/snap/snapcraft.yaml
Normal file
25
certbot-dns-cloudxns/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-cloudxns
|
||||
summary: CloudXNS DNS Authenticator plugin for Certbot
|
||||
description: CloudXNS DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-cloudxns
|
||||
|
||||
parts:
|
||||
certbot-dns-cloudxns:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,20 +7,27 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
'python-digitalocean>=1.11',
|
||||
'setuptools',
|
||||
'six',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-digitalocean/snap/snapcraft.yaml
Normal file
25
certbot-dns-digitalocean/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-digitalocean
|
||||
summary: DigitalOcean DNS Authenticator plugin for Certbot
|
||||
description: DigitalOcean DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-digitalocean
|
||||
|
||||
parts:
|
||||
certbot-dns-digitalocean:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,4 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -7,18 +7,25 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-dnsimple/snap/snapcraft.yaml
Normal file
25
certbot-dns-dnsimple/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-dnsimple
|
||||
summary: DNSimple DNS Authenticator plugin for Certbot
|
||||
description: DNSimple DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-dnsimple
|
||||
|
||||
parts:
|
||||
certbot-dns-dnsimple:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,19 +7,26 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-dnsmadeeasy/snap/snapcraft.yaml
Normal file
25
certbot-dns-dnsmadeeasy/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-dnsmadeeasy
|
||||
summary: DNS Made Easy DNS Authenticator plugin for Certbot
|
||||
description: DNS Made Easy DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-dnsmadeeasy
|
||||
|
||||
parts:
|
||||
certbot-dns-dnsmadeeasy:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,18 +7,25 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'dns-lexicon>=2.1.22',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-gehirn/snap/snapcraft.yaml
Normal file
25
certbot-dns-gehirn/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-gehirn
|
||||
summary: Gehirn Infrastructure Service DNS Authenticator plugin for Certbot
|
||||
description: Gehirn Infrastructure Service DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-gehirn
|
||||
|
||||
parts:
|
||||
certbot-dns-gehirn:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,13 +7,11 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
'google-api-python-client>=1.5.5',
|
||||
'oauth2client>=4.0',
|
||||
'setuptools',
|
||||
@@ -21,7 +20,16 @@ install_requires = [
|
||||
'httplib2'
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-google/snap/snapcraft.yaml
Normal file
25
certbot-dns-google/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-google
|
||||
summary: Google Cloud DNS Authenticator plugin for Certbot
|
||||
description: Google Cloud DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-google
|
||||
|
||||
parts:
|
||||
certbot-dns-google:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,18 +7,25 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'dns-lexicon>=2.2.3',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-linode/snap/snapcraft.yaml
Normal file
25
certbot-dns-linode/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-linode
|
||||
summary: Linode DNS Authenticator plugin for Certbot
|
||||
description: Linode DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-linode
|
||||
|
||||
parts:
|
||||
certbot-dns-linode:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,19 +7,26 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-luadns/snap/snapcraft.yaml
Normal file
25
certbot-dns-luadns/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-luadns
|
||||
summary: LuaDNS Authenticator plugin for Certbot
|
||||
description: LuaDNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-luadns
|
||||
|
||||
parts:
|
||||
certbot-dns-luadns:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,19 +7,26 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-nsone/snap/snapcraft.yaml
Normal file
25
certbot-dns-nsone/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-nsone
|
||||
summary: NS1 DNS Authenticator plugin for Certbot
|
||||
description: NS1 DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-nsone
|
||||
|
||||
parts:
|
||||
certbot-dns-nsone:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,19 +7,26 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-ovh/snap/snapcraft.yaml
Normal file
25
certbot-dns-ovh/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-ovh
|
||||
summary: OVH DNS Authenticator plugin for Certbot
|
||||
description: OVH DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-ovh
|
||||
|
||||
parts:
|
||||
certbot-dns-ovh:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,19 +7,26 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
'dnspython',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-rfc2136/snap/snapcraft.yaml
Normal file
25
certbot-dns-rfc2136/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-rfc2136
|
||||
summary: RFC 2136 DNS Authenticator plugin for Certbot
|
||||
description: RFC 2136 DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-rfc2136
|
||||
|
||||
parts:
|
||||
certbot-dns-rfc2136:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,19 +7,26 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
'boto3',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.29.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-route53/snap/snapcraft.yaml
Normal file
25
certbot-dns-route53/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-route53
|
||||
summary: Route53 DNS Authenticator plugin for Certbot
|
||||
description: Route53 DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-route53
|
||||
|
||||
parts:
|
||||
certbot-dns-route53:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -1,4 +1,5 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import os
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,18 +7,25 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
'dns-lexicon>=2.1.23',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
if not os.environ.get('EXCLUDE_CERTBOT_DEPS'):
|
||||
install_requires.extend([
|
||||
'acme>=0.31.0',
|
||||
'certbot>=1.1.0',
|
||||
])
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels '
|
||||
'to include certbot dependencies.')
|
||||
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
25
certbot-dns-sakuracloud/snap/snapcraft.yaml
Normal file
25
certbot-dns-sakuracloud/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: certbot-dns-sakuracloud
|
||||
summary: Sakura Cloud DNS Authenticator plugin for Certbot
|
||||
description: Sakura Cloud DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: devel
|
||||
base: core20
|
||||
adopt-info: certbot-dns-sakuracloud
|
||||
|
||||
parts:
|
||||
certbot-dns-sakuracloud:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- EXCLUDE_CERTBOT_DEPS: "True"
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
@@ -939,7 +939,8 @@ class NginxConfigurator(common.Installer):
|
||||
[self.conf('ctl'), "-c", self.nginx_conf, "-V"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
universal_newlines=True,
|
||||
env=util.env_no_snap_for_external_calls())
|
||||
text = proc.communicate()[1] # nginx prints output to stderr
|
||||
except (OSError, ValueError) as error:
|
||||
logger.debug(str(error), exc_info=True)
|
||||
@@ -1169,7 +1170,8 @@ def nginx_restart(nginx_ctl, nginx_conf):
|
||||
|
||||
"""
|
||||
try:
|
||||
proc = subprocess.Popen([nginx_ctl, "-c", nginx_conf, "-s", "reload"])
|
||||
proc = subprocess.Popen([nginx_ctl, "-c", nginx_conf, "-s", "reload"],
|
||||
env=util.env_no_snap_for_external_calls())
|
||||
proc.communicate()
|
||||
|
||||
if proc.returncode != 0:
|
||||
@@ -1179,7 +1181,7 @@ def nginx_restart(nginx_ctl, nginx_conf):
|
||||
with tempfile.TemporaryFile() as out:
|
||||
with tempfile.TemporaryFile() as err:
|
||||
nginx_proc = subprocess.Popen([nginx_ctl, "-c", nginx_conf],
|
||||
stdout=out, stderr=err)
|
||||
stdout=out, stderr=err, env=util.env_no_snap_for_external_calls())
|
||||
nginx_proc.communicate()
|
||||
if nginx_proc.returncode != 0:
|
||||
# Enter recovery routine...
|
||||
|
||||
@@ -3,9 +3,12 @@ import platform
|
||||
|
||||
FREEBSD_DARWIN_SERVER_ROOT = "/usr/local/etc/nginx"
|
||||
LINUX_SERVER_ROOT = "/etc/nginx"
|
||||
PKGSRC_SERVER_ROOT = "/usr/pkg/etc/nginx"
|
||||
|
||||
if platform.system() in ('FreeBSD', 'Darwin'):
|
||||
server_root_tmp = FREEBSD_DARWIN_SERVER_ROOT
|
||||
elif platform.system() in ('NetBSD',):
|
||||
server_root_tmp = PKGSRC_SERVER_ROOT
|
||||
else:
|
||||
server_root_tmp = LINUX_SERVER_ROOT
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==1.4.0
|
||||
certbot[dev]==1.4.0
|
||||
acme[dev]==1.6.0
|
||||
certbot[dev]==1.6.0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import LooseVersion
|
||||
import sys
|
||||
|
||||
from setuptools import __version__ as setuptools_version
|
||||
@@ -6,20 +6,20 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
version = '1.6.0.dev0'
|
||||
version = '1.7.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=1.4.0',
|
||||
'certbot>=1.4.0',
|
||||
'certbot>=1.6.0',
|
||||
'PyOpenSSL',
|
||||
'pyparsing>=1.5.5', # Python3 support
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2'))
|
||||
setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2'))
|
||||
if setuptools_known_environment_markers:
|
||||
install_requires.append('mock ; python_version < "3.3"')
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
|
||||
16
certbot.wrapper
Executable file
16
certbot.wrapper
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
join() {
|
||||
sep=$1
|
||||
first=$2
|
||||
if [ "$first" != "" ]; then
|
||||
shift 2
|
||||
echo -n "${first}"
|
||||
for item in "$@"; do echo -n "${sep}${item}"; done
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
paths=$(for plugin_snap in $(snap connections certbot|sed -n '2,$p'|awk '$1=="content[certbot-1]"{print $3}'|cut -d: -f1); do echo /snap/$plugin_snap/current/lib/python3.8/site-packages; done)
|
||||
export CERTBOT_PLUGIN_PATH=$(join : $paths)
|
||||
exec certbot "$@"
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
Certbot adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## 1.6.0 - master
|
||||
## 1.7.0 - master
|
||||
|
||||
### Added
|
||||
|
||||
*
|
||||
* Third-party plugins can be used without prefix (`plugin_name` instead of `dist_name:plugin_name`):
|
||||
this concerns the plugin name, CLI flags, and keys in credential files.
|
||||
The prefixed form is still supported but is deprecated, and will be removed in a future release.
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -18,6 +20,42 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 1.6.0 - 2020-07-07
|
||||
|
||||
### Added
|
||||
|
||||
* Certbot snaps are now available for the arm64 and armhf architectures.
|
||||
* Add minimal code to run Nginx plugin on NetBSD.
|
||||
* Make Certbot snap find externally snapped plugins
|
||||
* Function `certbot.compat.filesystem.umask` is a drop-in replacement for `os.umask`
|
||||
implementing umask for both UNIX and Windows systems.
|
||||
* Support for alternative certificate chains in the `acme` module.
|
||||
* Added `--preferred-chain <issuer CN>`. If a CA offers multiple certificate chains,
|
||||
it may be used to indicate to Certbot which chain should be preferred.
|
||||
* e.g. `--preferred-chain "DST Root CA X3"`
|
||||
|
||||
### Changed
|
||||
|
||||
* Allow session tickets to be disabled in Apache when mod_ssl is statically linked.
|
||||
* Generalize UI warning message on renewal rate limits
|
||||
* Certbot behaves similarly on Windows to on UNIX systems regarding umask, and
|
||||
the umask `022` is applied by default: all files/directories are not writable by anyone
|
||||
other than the user running Certbot and the system/admin users.
|
||||
* Read acmev1 Let's Encrypt server URL from renewal config as acmev2 URL to prepare
|
||||
for impending acmev1 deprecation.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Cloudflare API Tokens may now be restricted to individual zones.
|
||||
* Don't use `StrictVersion`, but `LooseVersion` to check version requirements with setuptools,
|
||||
to fix some packaging issues with libraries respecting PEP404 for version string,
|
||||
with doesn't match `StrictVersion` requirements.
|
||||
* Certbot output doesn't refer to SSL Labs due to confusing scoring behavior.
|
||||
* Fix paths when calling to programs outside of the Certbot Snap, fixing the apache and nginx
|
||||
plugins on, e.g., CentOS 7.
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 1.5.0 - 2020-06-02
|
||||
|
||||
### Added
|
||||
|
||||
@@ -73,9 +73,9 @@ ACME working area in github: https://github.com/ietf-wg-acme/acme
|
||||
|
||||
|build-status|
|
||||
|
||||
.. |build-status| image:: https://travis-ci.com/certbot/certbot.svg?branch=master
|
||||
:target: https://travis-ci.com/certbot/certbot
|
||||
:alt: Travis CI status
|
||||
.. |build-status| image:: https://img.shields.io/azure-devops/build/certbot/ba534f81-a483-4b9b-9b4e-a60bec8fee72/5/master
|
||||
:target: https://dev.azure.com/certbot/certbot/_build?definitionId=5
|
||||
:alt: Azure Pipelines CI status
|
||||
|
||||
.. Do not modify this comment unless you know what you're doing. tag:links-end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Certbot client."""
|
||||
|
||||
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
|
||||
__version__ = '1.6.0.dev0'
|
||||
__version__ = '1.7.0.dev0'
|
||||
|
||||
@@ -15,6 +15,7 @@ import zope.component
|
||||
|
||||
from acme import fields as acme_fields
|
||||
from acme import messages
|
||||
from acme.client import ClientBase # pylint: disable=unused-import
|
||||
from certbot import errors
|
||||
from certbot import interfaces
|
||||
from certbot import util
|
||||
@@ -39,6 +40,8 @@ class Account(object):
|
||||
|
||||
:ivar datetime.datetime creation_dt: Creation date and time (UTC).
|
||||
:ivar str creation_host: FQDN of host, where account has been created.
|
||||
:ivar str register_to_eff: If not None, Certbot will register the provided
|
||||
email during the account registration.
|
||||
|
||||
.. note:: ``creation_dt`` and ``creation_host`` are useful in
|
||||
cross-machine migration scenarios.
|
||||
@@ -46,15 +49,16 @@ class Account(object):
|
||||
"""
|
||||
creation_dt = acme_fields.RFC3339Field("creation_dt")
|
||||
creation_host = jose.Field("creation_host")
|
||||
register_to_eff = jose.Field("register_to_eff", omitempty=True)
|
||||
|
||||
def __init__(self, regr, key, meta=None):
|
||||
self.key = key
|
||||
self.regr = regr
|
||||
self.meta = self.Meta(
|
||||
# pyrfc3339 drops microseconds, make sure __eq__ is sane
|
||||
creation_dt=datetime.datetime.now(
|
||||
tz=pytz.UTC).replace(microsecond=0),
|
||||
creation_host=socket.getfqdn()) if meta is None else meta
|
||||
creation_dt=datetime.datetime.now(tz=pytz.UTC).replace(microsecond=0),
|
||||
creation_host=socket.getfqdn(),
|
||||
register_to_eff=None) if meta is None else meta
|
||||
|
||||
# try MD5, else use MD5 in non-security mode (e.g. for FIPS systems / RHEL)
|
||||
try:
|
||||
@@ -242,15 +246,47 @@ class AccountFileStorage(interfaces.AccountStorage):
|
||||
return self._load_for_server_path(account_id, self.config.server_path)
|
||||
|
||||
def save(self, account, client):
|
||||
self._save(account, client, regr_only=False)
|
||||
# type: (Account, ClientBase) -> None
|
||||
"""Create a new account.
|
||||
|
||||
def save_regr(self, account, acme):
|
||||
"""Save the registration resource.
|
||||
|
||||
:param Account account: account whose regr should be saved
|
||||
:param Account account: account to create
|
||||
:param ClientBase client: ACME client associated to the account
|
||||
|
||||
"""
|
||||
self._save(account, acme, regr_only=True)
|
||||
try:
|
||||
dir_path = self._prepare(account)
|
||||
self._create(account, dir_path)
|
||||
self._update_meta(account, dir_path)
|
||||
self._update_regr(account, client, dir_path)
|
||||
except IOError as error:
|
||||
raise errors.AccountStorageError(error)
|
||||
|
||||
def update_regr(self, account, client):
|
||||
# type: (Account, ClientBase) -> None
|
||||
"""Update the registration resource.
|
||||
|
||||
:param Account account: account to update
|
||||
:param ClientBase client: ACME client associated to the account
|
||||
|
||||
"""
|
||||
try:
|
||||
dir_path = self._prepare(account)
|
||||
self._update_regr(account, client, dir_path)
|
||||
except IOError as error:
|
||||
raise errors.AccountStorageError(error)
|
||||
|
||||
def update_meta(self, account):
|
||||
# type: (Account) -> None
|
||||
"""Update the meta resource.
|
||||
|
||||
:param Account account: account to update
|
||||
|
||||
"""
|
||||
try:
|
||||
dir_path = self._prepare(account)
|
||||
self._update_meta(account, dir_path)
|
||||
except IOError as error:
|
||||
raise errors.AccountStorageError(error)
|
||||
|
||||
def delete(self, account_id):
|
||||
"""Delete registration info from disk
|
||||
@@ -318,32 +354,36 @@ class AccountFileStorage(interfaces.AccountStorage):
|
||||
|
||||
return dir_path
|
||||
|
||||
def _save(self, account, acme, regr_only):
|
||||
def _prepare(self, account):
|
||||
# type: (Account) -> str
|
||||
account_dir_path = self._account_dir_path(account.id)
|
||||
util.make_or_verify_dir(account_dir_path, 0o700, self.config.strict_permissions)
|
||||
try:
|
||||
with open(self._regr_path(account_dir_path), "w") as regr_file:
|
||||
regr = account.regr
|
||||
# If we have a value for new-authz, save it for forwards
|
||||
# compatibility with older versions of Certbot. If we don't
|
||||
# have a value for new-authz, this is an ACMEv2 directory where
|
||||
# an older version of Certbot won't work anyway.
|
||||
if hasattr(acme.directory, "new-authz"):
|
||||
regr = RegistrationResourceWithNewAuthzrURI(
|
||||
new_authzr_uri=acme.directory.new_authz,
|
||||
body={},
|
||||
uri=regr.uri)
|
||||
else:
|
||||
regr = messages.RegistrationResource(
|
||||
body={},
|
||||
uri=regr.uri)
|
||||
regr_file.write(regr.json_dumps())
|
||||
if not regr_only:
|
||||
with util.safe_open(self._key_path(account_dir_path),
|
||||
"w", chmod=0o400) as key_file:
|
||||
key_file.write(account.key.json_dumps())
|
||||
with open(self._metadata_path(
|
||||
account_dir_path), "w") as metadata_file:
|
||||
metadata_file.write(account.meta.json_dumps())
|
||||
except IOError as error:
|
||||
raise errors.AccountStorageError(error)
|
||||
return account_dir_path
|
||||
|
||||
def _create(self, account, dir_path):
|
||||
# type: (Account, str) -> None
|
||||
with util.safe_open(self._key_path(dir_path), "w", chmod=0o400) as key_file:
|
||||
key_file.write(account.key.json_dumps())
|
||||
|
||||
def _update_regr(self, account, acme, dir_path):
|
||||
# type: (Account, ClientBase, str) -> None
|
||||
with open(self._regr_path(dir_path), "w") as regr_file:
|
||||
regr = account.regr
|
||||
# If we have a value for new-authz, save it for forwards
|
||||
# compatibility with older versions of Certbot. If we don't
|
||||
# have a value for new-authz, this is an ACMEv2 directory where
|
||||
# an older version of Certbot won't work anyway.
|
||||
if hasattr(acme.directory, "new-authz"):
|
||||
regr = RegistrationResourceWithNewAuthzrURI(
|
||||
new_authzr_uri=acme.directory.new_authz,
|
||||
body={},
|
||||
uri=regr.uri)
|
||||
else:
|
||||
regr = messages.RegistrationResource(
|
||||
body={},
|
||||
uri=regr.uri)
|
||||
regr_file.write(regr.json_dumps())
|
||||
|
||||
def _update_meta(self, account, dir_path):
|
||||
with open(self._metadata_path(dir_path), "w") as metadata_file:
|
||||
metadata_file.write(account.meta.json_dumps())
|
||||
|
||||
@@ -360,6 +360,11 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False):
|
||||
default=flag_default("strict_permissions"),
|
||||
help="Require that all configuration files are owned by the current "
|
||||
"user; only needed if your config is somewhere unsafe like /tmp/")
|
||||
helpful.add(
|
||||
[None, "certonly", "renew", "run"],
|
||||
"--preferred-chain", dest="preferred_chain",
|
||||
default=flag_default("preferred_chain"), help=config_help("preferred_chain")
|
||||
)
|
||||
helpful.add(
|
||||
["manual", "standalone", "certonly", "renew"],
|
||||
"--preferred-challenges", dest="pref_challs",
|
||||
|
||||
@@ -178,7 +178,7 @@ def register(config, account_storage, tos_cb=None):
|
||||
account.report_new_account(config)
|
||||
account_storage.save(acc, acme)
|
||||
|
||||
eff.handle_subscription(config)
|
||||
eff.prepare_subscription(config, acc)
|
||||
|
||||
return acc, acme
|
||||
|
||||
@@ -288,8 +288,16 @@ class Client(object):
|
||||
orderr = self._get_order_and_authorizations(csr.data, best_effort=False)
|
||||
|
||||
deadline = datetime.datetime.now() + datetime.timedelta(seconds=90)
|
||||
orderr = self.acme.finalize_order(orderr, deadline)
|
||||
cert, chain = crypto_util.cert_and_chain_from_fullchain(orderr.fullchain_pem)
|
||||
get_alt_chains = self.config.preferred_chain is not None
|
||||
orderr = self.acme.finalize_order(orderr, deadline,
|
||||
fetch_alternative_chains=get_alt_chains)
|
||||
fullchain = orderr.fullchain_pem
|
||||
if get_alt_chains and orderr.alternative_fullchains_pem:
|
||||
fullchain = crypto_util.find_chain_with_issuer([fullchain] + \
|
||||
orderr.alternative_fullchains_pem,
|
||||
self.config.preferred_chain,
|
||||
not self.config.dry_run)
|
||||
cert, chain = crypto_util.cert_and_chain_from_fullchain(fullchain)
|
||||
return cert.encode(), chain.encode()
|
||||
|
||||
def obtain_certificate(self, domains, old_keypath=None):
|
||||
@@ -389,6 +397,7 @@ class Client(object):
|
||||
|
||||
authzr = self.auth_handler.handle_authorizations(orderr, best_effort)
|
||||
return orderr.update(authorizations=authzr)
|
||||
|
||||
def obtain_and_enroll_certificate(self, domains, certname):
|
||||
"""Obtain and enroll certificate.
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ CLI_DEFAULTS = dict(
|
||||
uir=None,
|
||||
staple=None,
|
||||
strict_permissions=False,
|
||||
preferred_chain=None,
|
||||
pref_challs=[],
|
||||
validate_hooks=True,
|
||||
directory_hooks=True,
|
||||
@@ -120,6 +121,8 @@ CLI_DEFAULTS = dict(
|
||||
)
|
||||
STAGING_URI = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
|
||||
V1_URI = "https://acme-v01.api.letsencrypt.org/directory"
|
||||
|
||||
# The set of reasons for revoking a certificate is defined in RFC 5280 in
|
||||
# section 5.3.1. The reasons that users are allowed to submit are restricted to
|
||||
# those accepted by the ACME server implementation. They are listed in
|
||||
|
||||
@@ -4,32 +4,68 @@ import logging
|
||||
import requests
|
||||
import zope.component
|
||||
|
||||
from acme.magic_typing import Optional # pylint: disable=unused-import
|
||||
|
||||
from certbot import interfaces
|
||||
from certbot._internal import constants
|
||||
from certbot._internal.account import Account # pylint: disable=unused-import
|
||||
from certbot._internal.account import AccountFileStorage
|
||||
from certbot.interfaces import IConfig # pylint: disable=unused-import
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def handle_subscription(config):
|
||||
"""High level function to take care of EFF newsletter subscriptions.
|
||||
def prepare_subscription(config, acc):
|
||||
# type: (IConfig, Account) -> None
|
||||
"""High level function to store potential EFF newsletter subscriptions.
|
||||
|
||||
The user may be asked if they want to sign up for the newsletter if
|
||||
they have not already specified.
|
||||
they have not given their explicit approval or refusal using --eff-mail
|
||||
or --no-eff-mail flag.
|
||||
|
||||
:param .IConfig config: Client configuration.
|
||||
Decision about EFF subscription will be stored in the account metadata.
|
||||
|
||||
:param IConfig config: Client configuration.
|
||||
:param Account acc: Current client account.
|
||||
|
||||
"""
|
||||
if config.email is None:
|
||||
if config.eff_email:
|
||||
_report_failure("you didn't provide an e-mail address")
|
||||
if config.eff_email is False:
|
||||
return
|
||||
if config.eff_email is None:
|
||||
config.eff_email = _want_subscription()
|
||||
if config.eff_email:
|
||||
subscribe(config.email)
|
||||
if config.eff_email is True:
|
||||
if config.email is None:
|
||||
_report_failure("you didn't provide an e-mail address")
|
||||
else:
|
||||
acc.meta = acc.meta.update(register_to_eff=config.email)
|
||||
elif config.email and _want_subscription():
|
||||
acc.meta = acc.meta.update(register_to_eff=config.email)
|
||||
|
||||
if acc.meta.register_to_eff:
|
||||
storage = AccountFileStorage(config)
|
||||
storage.update_meta(acc)
|
||||
|
||||
|
||||
def handle_subscription(config, acc):
|
||||
# type: (IConfig, Account) -> None
|
||||
"""High level function to take care of EFF newsletter subscriptions.
|
||||
|
||||
Once subscription is handled, it will not be handled again.
|
||||
|
||||
:param IConfig config: Client configuration.
|
||||
:param Account acc: Current client account.
|
||||
|
||||
"""
|
||||
if config.dry_run:
|
||||
return
|
||||
if acc.meta.register_to_eff:
|
||||
subscribe(acc.meta.register_to_eff)
|
||||
|
||||
acc.meta = acc.meta.update(register_to_eff=None)
|
||||
storage = AccountFileStorage(config)
|
||||
storage.update_meta(acc)
|
||||
|
||||
|
||||
def _want_subscription():
|
||||
# type: () -> bool
|
||||
"""Does the user want to be subscribed to the EFF newsletter?
|
||||
|
||||
:returns: True if we should subscribe the user, otherwise, False
|
||||
@@ -37,16 +73,17 @@ def _want_subscription():
|
||||
|
||||
"""
|
||||
prompt = (
|
||||
'Would you be willing to share your email address with the '
|
||||
"Electronic Frontier Foundation, a founding partner of the Let's "
|
||||
'Encrypt project and the non-profit organization that develops '
|
||||
"Certbot? We'd like to send you email about our work encrypting "
|
||||
'Would you be willing, once your first certificate is successfully issued, '
|
||||
'to share your email address with the Electronic Frontier Foundation, a '
|
||||
"founding partner of the Let's Encrypt project and the non-profit organization "
|
||||
"that develops Certbot? We'd like to send you email about our work encrypting "
|
||||
"the web, EFF news, campaigns, and ways to support digital freedom. ")
|
||||
display = zope.component.getUtility(interfaces.IDisplay)
|
||||
return display.yesno(prompt, default=False)
|
||||
|
||||
|
||||
def subscribe(email):
|
||||
# type: (str) -> None
|
||||
"""Subscribe the user to the EFF mailing list.
|
||||
|
||||
:param str email: the e-mail address to subscribe
|
||||
@@ -56,11 +93,13 @@ def subscribe(email):
|
||||
data = {'data_type': 'json',
|
||||
'email': email,
|
||||
'form_id': 'eff_supporters_library_subscribe_form'}
|
||||
logger.info('Subscribe to the EFF mailing list (email: %s).', email)
|
||||
logger.debug('Sending POST request to %s:\n%s', url, data)
|
||||
_check_response(requests.post(url, data=data))
|
||||
|
||||
|
||||
def _check_response(response):
|
||||
# type: (requests.Response) -> None
|
||||
"""Check for errors in the server's response.
|
||||
|
||||
If an error occurred, it will be reported to the user.
|
||||
@@ -81,6 +120,7 @@ def _check_response(response):
|
||||
|
||||
|
||||
def _report_failure(reason=None):
|
||||
# type: (Optional[str]) -> None
|
||||
"""Notify the user of failing to sign them up for the newsletter.
|
||||
|
||||
:param reason: a phrase describing what the problem was
|
||||
|
||||
@@ -228,7 +228,7 @@ def _run_hook(cmd_name, shell_cmd):
|
||||
:type shell_cmd: `list` of `str` or `str`
|
||||
|
||||
:returns: stderr if there was any"""
|
||||
err, _ = misc.execute_command(cmd_name, shell_cmd)
|
||||
err, _ = misc.execute_command(cmd_name, shell_cmd, env=util.env_no_snap_for_external_calls())
|
||||
return err
|
||||
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ def _handle_identical_cert_request(config, lineage):
|
||||
elif config.verb == "certonly":
|
||||
keep_opt = "Keep the existing certificate for now"
|
||||
choices = [keep_opt,
|
||||
"Renew & replace the cert (limit ~5 per 7 days)"]
|
||||
"Renew & replace the cert (may be subject to CA rate limits)"]
|
||||
|
||||
display = zope.component.getUtility(interfaces.IDisplay)
|
||||
response = display.menu(question, choices,
|
||||
@@ -721,11 +721,12 @@ def update_account(config, unused_plugins):
|
||||
# the v2 uri. Since it's the same object on disk, put it back to the v1 uri
|
||||
# so that we can also continue to use the account object with acmev1.
|
||||
acc.regr = acc.regr.update(uri=prev_regr_uri)
|
||||
account_storage.save_regr(acc, cb_client.acme)
|
||||
eff.handle_subscription(config)
|
||||
account_storage.update_regr(acc, cb_client.acme)
|
||||
eff.prepare_subscription(config, acc)
|
||||
add_msg("Your e-mail address was updated to {0}.".format(config.email))
|
||||
return None
|
||||
|
||||
|
||||
def _install_cert(config, le_client, domains, lineage=None):
|
||||
"""Install a cert
|
||||
|
||||
@@ -1116,6 +1117,7 @@ def run(config, plugins):
|
||||
display_ops.success_renewal(domains)
|
||||
|
||||
_suggest_donation_if_appropriate(config)
|
||||
eff.handle_subscription(config, le_client.account)
|
||||
return None
|
||||
|
||||
|
||||
@@ -1189,6 +1191,7 @@ def renew_cert(config, plugins, lineage):
|
||||
notify("new certificate deployed with reload of {0} server; fullchain is {1}".format(
|
||||
config.installer, lineage.fullchain), pause=False)
|
||||
|
||||
|
||||
def certonly(config, plugins):
|
||||
"""Authenticate & obtain cert, but do not install it.
|
||||
|
||||
@@ -1220,6 +1223,7 @@ def certonly(config, plugins):
|
||||
cert_path, fullchain_path = _csr_get_and_save_cert(config, le_client)
|
||||
_report_new_cert(config, cert_path, fullchain_path)
|
||||
_suggest_donation_if_appropriate(config)
|
||||
eff.handle_subscription(config, le_client.account)
|
||||
return
|
||||
|
||||
domains, certname = _find_domains_or_certname(config, installer)
|
||||
@@ -1237,6 +1241,8 @@ def certonly(config, plugins):
|
||||
key_path = lineage.key_path if lineage else None
|
||||
_report_new_cert(config, cert_path, fullchain_path, key_path)
|
||||
_suggest_donation_if_appropriate(config)
|
||||
eff.handle_subscription(config, le_client.account)
|
||||
|
||||
|
||||
def renew(config, unused_plugins):
|
||||
"""Renew previously-obtained certificates.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import collections
|
||||
import itertools
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import pkg_resources
|
||||
import six
|
||||
@@ -12,6 +13,7 @@ from acme.magic_typing import Dict
|
||||
from certbot import errors
|
||||
from certbot import interfaces
|
||||
from certbot._internal import constants
|
||||
from certbot.compat import os
|
||||
|
||||
try:
|
||||
# Python 3.3+
|
||||
@@ -21,47 +23,58 @@ except ImportError: # pragma: no cover
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
PREFIX_FREE_DISTRIBUTIONS = [
|
||||
"certbot",
|
||||
"certbot-apache",
|
||||
"certbot-dns-cloudflare",
|
||||
"certbot-dns-cloudxns",
|
||||
"certbot-dns-digitalocean",
|
||||
"certbot-dns-dnsimple",
|
||||
"certbot-dns-dnsmadeeasy",
|
||||
"certbot-dns-gehirn",
|
||||
"certbot-dns-google",
|
||||
"certbot-dns-linode",
|
||||
"certbot-dns-luadns",
|
||||
"certbot-dns-nsone",
|
||||
"certbot-dns-ovh",
|
||||
"certbot-dns-rfc2136",
|
||||
"certbot-dns-route53",
|
||||
"certbot-dns-sakuracloud",
|
||||
"certbot-nginx",
|
||||
]
|
||||
"""Distributions for which prefix will be omitted."""
|
||||
|
||||
|
||||
class PluginEntryPoint(object):
|
||||
"""Plugin entry point."""
|
||||
|
||||
PREFIX_FREE_DISTRIBUTIONS = [
|
||||
"certbot",
|
||||
"certbot-apache",
|
||||
"certbot-dns-cloudflare",
|
||||
"certbot-dns-cloudxns",
|
||||
"certbot-dns-digitalocean",
|
||||
"certbot-dns-dnsimple",
|
||||
"certbot-dns-dnsmadeeasy",
|
||||
"certbot-dns-gehirn",
|
||||
"certbot-dns-google",
|
||||
"certbot-dns-linode",
|
||||
"certbot-dns-luadns",
|
||||
"certbot-dns-nsone",
|
||||
"certbot-dns-ovh",
|
||||
"certbot-dns-rfc2136",
|
||||
"certbot-dns-route53",
|
||||
"certbot-dns-sakuracloud",
|
||||
"certbot-nginx",
|
||||
]
|
||||
"""Distributions for which prefix will be omitted."""
|
||||
|
||||
# this object is mutable, don't allow it to be hashed!
|
||||
__hash__ = None # type: ignore
|
||||
|
||||
def __init__(self, entry_point):
|
||||
self.name = self.entry_point_to_plugin_name(entry_point)
|
||||
def __init__(self, entry_point, with_prefix=False):
|
||||
self.name = self.entry_point_to_plugin_name(entry_point, with_prefix)
|
||||
self.plugin_cls = entry_point.load()
|
||||
self.entry_point = entry_point
|
||||
self.warning_message = None
|
||||
self._initialized = None
|
||||
self._prepared = None
|
||||
self._hidden = False
|
||||
self._long_description = None
|
||||
|
||||
def check_name(self, name):
|
||||
"""Check if the name refers to this plugin."""
|
||||
if name == self.name:
|
||||
if self.warning_message:
|
||||
logger.warning(self.warning_message)
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def entry_point_to_plugin_name(cls, entry_point):
|
||||
def entry_point_to_plugin_name(cls, entry_point, with_prefix):
|
||||
"""Unique plugin name for an ``entry_point``"""
|
||||
if entry_point.dist.key in cls.PREFIX_FREE_DISTRIBUTIONS:
|
||||
return entry_point.name
|
||||
return entry_point.dist.key + ":" + entry_point.name
|
||||
if with_prefix:
|
||||
return entry_point.dist.key + ":" + entry_point.name
|
||||
return entry_point.name
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
@@ -76,15 +89,25 @@ class PluginEntryPoint(object):
|
||||
@property
|
||||
def long_description(self):
|
||||
"""Long description of the plugin."""
|
||||
if self._long_description:
|
||||
return self._long_description
|
||||
try:
|
||||
return self.plugin_cls.long_description
|
||||
except AttributeError:
|
||||
return self.description
|
||||
|
||||
@long_description.setter
|
||||
def long_description(self, description):
|
||||
self._long_description = description
|
||||
|
||||
@property
|
||||
def hidden(self):
|
||||
"""Should this plugin be hidden from UI?"""
|
||||
return getattr(self.plugin_cls, "hidden", False)
|
||||
return self._hidden or getattr(self.plugin_cls, "hidden", False)
|
||||
|
||||
@hidden.setter
|
||||
def hidden(self, hide):
|
||||
self._hidden = hide
|
||||
|
||||
def ifaces(self, *ifaces_groups):
|
||||
"""Does plugin implements specified interface groups?"""
|
||||
@@ -198,22 +221,46 @@ class PluginsRegistry(Mapping):
|
||||
def find_all(cls):
|
||||
"""Find plugins using setuptools entry points."""
|
||||
plugins = {} # type: Dict[str, PluginEntryPoint]
|
||||
plugin_paths_string = os.getenv('CERTBOT_PLUGIN_PATH')
|
||||
plugin_paths = plugin_paths_string.split(':') if plugin_paths_string else []
|
||||
# XXX should ensure this only happens once
|
||||
sys.path.extend(plugin_paths)
|
||||
for plugin_path in plugin_paths:
|
||||
pkg_resources.working_set.add_entry(plugin_path)
|
||||
entry_points = itertools.chain(
|
||||
pkg_resources.iter_entry_points(
|
||||
constants.SETUPTOOLS_PLUGINS_ENTRY_POINT),
|
||||
pkg_resources.iter_entry_points(
|
||||
constants.OLD_SETUPTOOLS_PLUGINS_ENTRY_POINT),)
|
||||
for entry_point in entry_points:
|
||||
plugin_ep = PluginEntryPoint(entry_point)
|
||||
assert plugin_ep.name not in plugins, (
|
||||
"PREFIX_FREE_DISTRIBUTIONS messed up")
|
||||
if interfaces.IPluginFactory.providedBy(plugin_ep.plugin_cls):
|
||||
plugins[plugin_ep.name] = plugin_ep
|
||||
else: # pragma: no cover
|
||||
logger.warning(
|
||||
"%r does not provide IPluginFactory, skipping", plugin_ep)
|
||||
plugin_ep = cls._load_entry_point(entry_point, plugins, with_prefix=False)
|
||||
if entry_point.dist.key not in PREFIX_FREE_DISTRIBUTIONS:
|
||||
prefixed_plugin_ep = cls._load_entry_point(entry_point, plugins, with_prefix=True)
|
||||
prefixed_plugin_ep.hidden = True
|
||||
message = (
|
||||
"Plugin legacy name {0} may be removed in a future version. "
|
||||
"Please use {1} instead.").format(prefixed_plugin_ep.name, plugin_ep.name)
|
||||
prefixed_plugin_ep.warning_message = message
|
||||
prefixed_plugin_ep.long_description = "(WARNING: {0}) {1}".format(
|
||||
message, prefixed_plugin_ep.long_description)
|
||||
|
||||
return cls(plugins)
|
||||
|
||||
@classmethod
|
||||
def _load_entry_point(cls, entry_point, plugins, with_prefix):
|
||||
plugin_ep = PluginEntryPoint(entry_point, with_prefix)
|
||||
if plugin_ep.name in plugins:
|
||||
other_ep = plugins[plugin_ep.name]
|
||||
raise Exception("Duplicate plugin name {0} from {1} and {2}.".format(
|
||||
plugin_ep.name, plugin_ep.entry_point.dist.key, other_ep.entry_point.dist.key))
|
||||
if interfaces.IPluginFactory.providedBy(plugin_ep.plugin_cls):
|
||||
plugins[plugin_ep.name] = plugin_ep
|
||||
else: # pragma: no cover
|
||||
logger.warning(
|
||||
"%r does not provide IPluginFactory, skipping", plugin_ep)
|
||||
|
||||
return plugin_ep
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self._plugins[name]
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from certbot import achallenges # pylint: disable=unused-import
|
||||
from certbot import errors
|
||||
from certbot import interfaces
|
||||
from certbot import reverter
|
||||
from certbot import util
|
||||
from certbot._internal import hooks
|
||||
from certbot.compat import misc
|
||||
from certbot.compat import os
|
||||
@@ -36,8 +37,8 @@ class Authenticator(common.Plugin):
|
||||
'is the validation string, and $CERTBOT_TOKEN is the filename of the '
|
||||
'resource requested when performing an HTTP-01 challenge. An additional '
|
||||
'cleanup script can also be provided and can use the additional variable '
|
||||
'$CERTBOT_AUTH_OUTPUT which contains the stdout output from the auth script.'
|
||||
'For both authenticator and cleanup script, on HTTP-01 and DNS-01 challenges,'
|
||||
'$CERTBOT_AUTH_OUTPUT which contains the stdout output from the auth script. '
|
||||
'For both authenticator and cleanup script, on HTTP-01 and DNS-01 challenges, '
|
||||
'$CERTBOT_REMAINING_CHALLENGES will be equal to the number of challenges that '
|
||||
'remain after the current one, and $CERTBOT_ALL_DOMAINS contains a comma-separated '
|
||||
'list of all domains that are challenged for the current certificate.')
|
||||
@@ -187,4 +188,5 @@ permitted by DNS standards.)
|
||||
self.reverter.recovery_routine()
|
||||
|
||||
def _execute_hook(self, hook_name):
|
||||
return misc.execute_command(self.option_name(hook_name), self.conf(hook_name))
|
||||
return misc.execute_command(self.option_name(hook_name), self.conf(hook_name),
|
||||
env=util.env_no_snap_for_external_calls())
|
||||
|
||||
@@ -38,6 +38,7 @@ def pick_authenticator(
|
||||
return pick_plugin(
|
||||
config, default, plugins, question, (interfaces.IAuthenticator,))
|
||||
|
||||
|
||||
def get_unprepared_installer(config, plugins):
|
||||
"""
|
||||
Get an unprepared interfaces.IInstaller object.
|
||||
@@ -53,7 +54,7 @@ def get_unprepared_installer(config, plugins):
|
||||
_, req_inst = cli_plugin_requests(config)
|
||||
if not req_inst:
|
||||
return None
|
||||
installers = plugins.filter(lambda p_ep: p_ep.name == req_inst)
|
||||
installers = plugins.filter(lambda p_ep: p_ep.check_name(req_inst))
|
||||
installers.init(config)
|
||||
installers = installers.verify((interfaces.IInstaller,))
|
||||
if len(installers) > 1:
|
||||
@@ -67,6 +68,7 @@ def get_unprepared_installer(config, plugins):
|
||||
raise errors.PluginSelectionError(
|
||||
"Could not select or initialize the requested installer %s." % req_inst)
|
||||
|
||||
|
||||
def pick_plugin(config, default, plugins, question, ifaces):
|
||||
"""Pick plugin.
|
||||
|
||||
@@ -84,7 +86,7 @@ def pick_plugin(config, default, plugins, question, ifaces):
|
||||
"""
|
||||
if default is not None:
|
||||
# throw more UX-friendly error if default not in plugins
|
||||
filtered = plugins.filter(lambda p_ep: p_ep.name == default)
|
||||
filtered = plugins.filter(lambda p_ep: p_ep.check_name(default))
|
||||
else:
|
||||
if config.noninteractive_mode:
|
||||
# it's really bad to auto-select the single available plugin in
|
||||
|
||||
@@ -164,7 +164,7 @@ to serve all files under specified web root ({0})."""
|
||||
# Change the permissions to be writable (GH #1389)
|
||||
# Umask is used instead of chmod to ensure the client can also
|
||||
# run as non-root (GH #1795)
|
||||
old_umask = os.umask(0o022)
|
||||
old_umask = filesystem.umask(0o022)
|
||||
try:
|
||||
# We ignore the last prefix in the next iteration,
|
||||
# as it does not correspond to a folder path ('/' or 'C:')
|
||||
@@ -191,7 +191,7 @@ to serve all files under specified web root ({0})."""
|
||||
"Couldn't create root for {0} http-01 "
|
||||
"challenge responses: {1}".format(name, exception))
|
||||
finally:
|
||||
os.umask(old_umask)
|
||||
filesystem.umask(old_umask)
|
||||
|
||||
def _get_validation_path(self, root_path, achall): # pylint: no-self-use
|
||||
return os.path.join(root_path, achall.chall.encode("token"))
|
||||
@@ -204,13 +204,13 @@ to serve all files under specified web root ({0})."""
|
||||
logger.debug("Attempting to save validation to %s", validation_path)
|
||||
|
||||
# Change permissions to be world-readable, owner-writable (GH #1795)
|
||||
old_umask = os.umask(0o022)
|
||||
old_umask = filesystem.umask(0o022)
|
||||
|
||||
try:
|
||||
with safe_open(validation_path, mode="wb", chmod=0o644) as validation_file:
|
||||
validation_file.write(validation.encode())
|
||||
finally:
|
||||
os.umask(old_umask)
|
||||
filesystem.umask(old_umask)
|
||||
|
||||
self.performed[root_path].add(achall)
|
||||
return response
|
||||
|
||||
@@ -19,6 +19,7 @@ from certbot import errors
|
||||
from certbot import interfaces
|
||||
from certbot import util
|
||||
from certbot._internal import cli
|
||||
from certbot._internal import constants
|
||||
from certbot._internal import hooks
|
||||
from certbot._internal import storage
|
||||
from certbot._internal import updater
|
||||
@@ -33,7 +34,8 @@ logger = logging.getLogger(__name__)
|
||||
# the renewal configuration process loses this information.
|
||||
STR_CONFIG_ITEMS = ["config_dir", "logs_dir", "work_dir", "user_agent",
|
||||
"server", "account", "authenticator", "installer",
|
||||
"renew_hook", "pre_hook", "post_hook", "http01_address"]
|
||||
"renew_hook", "pre_hook", "post_hook", "http01_address",
|
||||
"preferred_chain"]
|
||||
INT_CONFIG_ITEMS = ["rsa_key_size", "http01_port"]
|
||||
BOOL_CONFIG_ITEMS = ["must_staple", "allow_subset_of_names", "reuse_key",
|
||||
"autorenew"]
|
||||
@@ -243,16 +245,28 @@ def _restore_int(name, value):
|
||||
raise errors.Error("Expected a numeric value for {0}".format(name))
|
||||
|
||||
|
||||
def _restore_str(unused_name, value):
|
||||
def _restore_str(name, value):
|
||||
"""Restores a string key-value pair from a renewal config file.
|
||||
|
||||
:param str unused_name: option name
|
||||
:param str name: option name
|
||||
:param str value: option value
|
||||
|
||||
:returns: converted option value to be stored in the runtime config
|
||||
:rtype: str or None
|
||||
|
||||
"""
|
||||
# Previous to v0.5.0, Certbot always stored the `server` URL in the renewal config,
|
||||
# resulting in configs which explicitly use the deprecated ACMEv1 URL, today
|
||||
# preventing an automatic transition to the default modern ACME URL.
|
||||
# (https://github.com/certbot/certbot/issues/7978#issuecomment-625442870)
|
||||
# As a mitigation, this function reinterprets the value of the `server` parameter if
|
||||
# necessary, replacing the ACMEv1 URL with the default ACME URL. It is still possible
|
||||
# to override this choice with the explicit `--server` CLI flag.
|
||||
if name == "server" and value == constants.V1_URI:
|
||||
logger.info("Using server %s instead of legacy %s",
|
||||
constants.CLI_DEFAULTS["server"], value)
|
||||
return constants.CLI_DEFAULTS["server"]
|
||||
|
||||
return None if value == "None" else value
|
||||
|
||||
|
||||
|
||||
@@ -21,17 +21,32 @@ else:
|
||||
POSIX_MODE = False
|
||||
|
||||
|
||||
# Windows umask implementation, since Windows does not have a concept of umask by default.
|
||||
# We choose 022 as initial value since it is the default one on most Linux distributions, and
|
||||
# it is a decent choice to not have write permissions for group owner and everybody by default.
|
||||
# We use a class here to avoid needing to define a global variable, and the potential mistakes
|
||||
# that could happen with this kind of pattern.
|
||||
class _WindowsUmask:
|
||||
"""Store the current umask to apply on Windows"""
|
||||
def __init__(self):
|
||||
self.mask = 0o022
|
||||
|
||||
|
||||
_WINDOWS_UMASK = _WindowsUmask()
|
||||
|
||||
|
||||
def chmod(file_path, mode):
|
||||
# type: (str, int) -> None
|
||||
"""
|
||||
Apply a POSIX mode on given file_path:
|
||||
* for Linux, the POSIX mode will be directly applied using chmod,
|
||||
* for Windows, the POSIX mode will be translated into a Windows DACL that make sense for
|
||||
Certbot context, and applied to the file using kernel calls.
|
||||
|
||||
- for Linux, the POSIX mode will be directly applied using chmod,
|
||||
- for Windows, the POSIX mode will be translated into a Windows DACL that make sense for
|
||||
Certbot context, and applied to the file using kernel calls.
|
||||
|
||||
The definition of the Windows DACL that correspond to a POSIX mode, in the context of Certbot,
|
||||
is explained at https://github.com/certbot/certbot/issues/6356 and is implemented by the
|
||||
method _generate_windows_flags().
|
||||
method `_generate_windows_flags()`.
|
||||
|
||||
:param str file_path: Path of the file
|
||||
:param int mode: POSIX mode to apply
|
||||
@@ -42,6 +57,24 @@ def chmod(file_path, mode):
|
||||
_apply_win_mode(file_path, mode)
|
||||
|
||||
|
||||
def umask(mask):
|
||||
# type: (int) -> int
|
||||
"""
|
||||
Set the current numeric umask and return the previous umask. On Linux, the built-in umask
|
||||
method is used. On Windows, our Certbot-side implementation is used.
|
||||
|
||||
:param int mask: The user file-creation mode mask to apply.
|
||||
:rtype: int
|
||||
:return: The previous umask value.
|
||||
"""
|
||||
if POSIX_MODE:
|
||||
return os.umask(mask)
|
||||
|
||||
previous_umask = _WINDOWS_UMASK.mask
|
||||
_WINDOWS_UMASK.mask = mask
|
||||
return previous_umask
|
||||
|
||||
|
||||
# One could ask why there is no copy_ownership() function, or even a reimplementation
|
||||
# of os.chown() that would modify the ownership of file without touching the mode itself.
|
||||
# This is because on Windows, it would require recalculating the existing DACL against
|
||||
@@ -57,6 +90,7 @@ def copy_ownership_and_apply_mode(src, dst, mode, copy_user, copy_group):
|
||||
Copy ownership (user and optionally group on Linux) from the source to the
|
||||
destination, then apply given mode in compatible way for Linux and Windows.
|
||||
This replaces the os.chown command.
|
||||
|
||||
:param str src: Path of the source file
|
||||
:param str dst: Path of the destination file
|
||||
:param int mode: Permission mode to apply on the destination file
|
||||
@@ -88,6 +122,7 @@ def copy_ownership_and_mode(src, dst, copy_user=True, copy_group=True):
|
||||
"""
|
||||
Copy ownership (user and optionally group on Linux) and mode/DACL
|
||||
from the source to the destination.
|
||||
|
||||
:param str src: Path of the source file
|
||||
:param str dst: Path of the destination file
|
||||
:param bool copy_user: Copy user if `True`
|
||||
@@ -113,6 +148,7 @@ def check_mode(file_path, mode):
|
||||
Check if the given mode matches the permissions of the given file.
|
||||
On Linux, will make a direct comparison, on Windows, mode will be compared against
|
||||
the security model.
|
||||
|
||||
:param str file_path: Path of the file
|
||||
:param int mode: POSIX mode to test
|
||||
:rtype: bool
|
||||
@@ -128,6 +164,7 @@ def check_owner(file_path):
|
||||
# type: (str) -> bool
|
||||
"""
|
||||
Check if given file is owned by current user.
|
||||
|
||||
:param str file_path: File path to check
|
||||
:rtype: bool
|
||||
:return: True if given file is owned by current user, False otherwise.
|
||||
@@ -150,6 +187,7 @@ def check_permissions(file_path, mode):
|
||||
# type: (str, int) -> bool
|
||||
"""
|
||||
Check if given file has the given mode and is owned by current user.
|
||||
|
||||
:param str file_path: File path to check
|
||||
:param int mode: POSIX mode to check
|
||||
:rtype: bool
|
||||
@@ -163,6 +201,7 @@ def open(file_path, flags, mode=0o777): # pylint: disable=redefined-builtin
|
||||
"""
|
||||
Wrapper of original os.open function, that will ensure on Windows that given mode
|
||||
is correctly applied.
|
||||
|
||||
:param str file_path: The file path to open
|
||||
:param int flags: Flags to apply on file while opened
|
||||
:param int mode: POSIX mode to apply on file when opened,
|
||||
@@ -171,7 +210,7 @@ def open(file_path, flags, mode=0o777): # pylint: disable=redefined-builtin
|
||||
:rtype: int
|
||||
:raise: OSError(errno.EEXIST) if the file already exists and os.O_CREAT & os.O_EXCL are set,
|
||||
OSError(errno.EACCES) on Windows if the file already exists and is a directory, and
|
||||
os.O_CREAT is set.
|
||||
os.O_CREAT is set.
|
||||
"""
|
||||
if POSIX_MODE:
|
||||
# On Linux, invoke os.open directly.
|
||||
@@ -187,7 +226,7 @@ def open(file_path, flags, mode=0o777): # pylint: disable=redefined-builtin
|
||||
attributes = win32security.SECURITY_ATTRIBUTES()
|
||||
security = attributes.SECURITY_DESCRIPTOR
|
||||
user = _get_current_user()
|
||||
dacl = _generate_dacl(user, mode)
|
||||
dacl = _generate_dacl(user, mode, _WINDOWS_UMASK.mask)
|
||||
# We set second parameter to 0 (`False`) to say that this security descriptor is
|
||||
# NOT constructed from a default mechanism, but is explicitly set by the user.
|
||||
# See https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptorowner # pylint: disable=line-too-long
|
||||
@@ -232,32 +271,32 @@ def makedirs(file_path, mode=0o777):
|
||||
"""
|
||||
Rewrite of original os.makedirs function, that will ensure on Windows that given mode
|
||||
is correctly applied.
|
||||
|
||||
:param str file_path: The file path to open
|
||||
:param int mode: POSIX mode to apply on leaf directory when created, Python defaults
|
||||
will be applied if ``None``
|
||||
"""
|
||||
if POSIX_MODE:
|
||||
# Since Python 3.7, os.makedirs does not set the given mode to the intermediate directories
|
||||
# that could be created in the process. To keep things safe and consistent on all
|
||||
# Python versions, we set the umask accordingly to have all directories (intermediate and
|
||||
# leaf) created with the given mode.
|
||||
current_umask = os.umask(0)
|
||||
current_umask = umask(0)
|
||||
try:
|
||||
# Since Python 3.7, os.makedirs does not set the given mode to the intermediate
|
||||
# directories that could be created in the process. To keep things safe and consistent
|
||||
# on all Python versions, we set the umask accordingly to have all directories
|
||||
# (intermediate and leaf) created with the given mode.
|
||||
umask(current_umask | 0o777 ^ mode)
|
||||
|
||||
if POSIX_MODE:
|
||||
return os.makedirs(file_path, mode)
|
||||
|
||||
orig_mkdir_fn = os.mkdir
|
||||
try:
|
||||
os.umask(current_umask | 0o777 ^ mode)
|
||||
# As we know that os.mkdir is called internally by os.makedirs, we will swap the
|
||||
# function in os module for the time of makedirs execution on Windows.
|
||||
os.mkdir = mkdir # type: ignore
|
||||
return os.makedirs(file_path, mode)
|
||||
finally:
|
||||
os.umask(current_umask)
|
||||
|
||||
# TODO: Windows does not support umask. A specific PR (#7967) is handling this, and will need
|
||||
# to add appropriate umask call for the Windows part of the logic below.
|
||||
orig_mkdir_fn = os.mkdir
|
||||
try:
|
||||
# As we know that os.mkdir is called internally by os.makedirs, we will swap the function in
|
||||
# os module for the time of makedirs execution on Windows.
|
||||
os.mkdir = mkdir # type: ignore
|
||||
return os.makedirs(file_path, mode)
|
||||
os.mkdir = orig_mkdir_fn
|
||||
finally:
|
||||
os.mkdir = orig_mkdir_fn
|
||||
umask(current_umask)
|
||||
|
||||
|
||||
def mkdir(file_path, mode=0o777):
|
||||
@@ -265,6 +304,7 @@ def mkdir(file_path, mode=0o777):
|
||||
"""
|
||||
Rewrite of original os.mkdir function, that will ensure on Windows that given mode
|
||||
is correctly applied.
|
||||
|
||||
:param str file_path: The file path to open
|
||||
:param int mode: POSIX mode to apply on directory when created, Python defaults
|
||||
will be applied if ``None``
|
||||
@@ -275,7 +315,7 @@ def mkdir(file_path, mode=0o777):
|
||||
attributes = win32security.SECURITY_ATTRIBUTES()
|
||||
security = attributes.SECURITY_DESCRIPTOR
|
||||
user = _get_current_user()
|
||||
dacl = _generate_dacl(user, mode)
|
||||
dacl = _generate_dacl(user, mode, _WINDOWS_UMASK.mask)
|
||||
security.SetSecurityDescriptorOwner(user, False)
|
||||
security.SetSecurityDescriptorDacl(1, dacl, 0)
|
||||
|
||||
@@ -295,6 +335,7 @@ def replace(src, dst):
|
||||
# type: (str, str) -> None
|
||||
"""
|
||||
Rename a file to a destination path and handles situations where the destination exists.
|
||||
|
||||
:param str src: The current file path.
|
||||
:param str dst: The new file path.
|
||||
"""
|
||||
@@ -312,6 +353,10 @@ def realpath(file_path):
|
||||
"""
|
||||
Find the real path for the given path. This method resolves symlinks, including
|
||||
recursive symlinks, and is protected against symlinks that creates an infinite loop.
|
||||
|
||||
:param str file_path: The path to resolve
|
||||
:returns: The real path for the given path
|
||||
:rtype: str
|
||||
"""
|
||||
original_path = file_path
|
||||
|
||||
@@ -348,6 +393,7 @@ def is_executable(path):
|
||||
# type: (str) -> bool
|
||||
"""
|
||||
Is path an executable file?
|
||||
|
||||
:param str path: path to test
|
||||
:return: True if path is an executable file
|
||||
:rtype: bool
|
||||
@@ -361,7 +407,8 @@ def is_executable(path):
|
||||
def has_world_permissions(path):
|
||||
# type: (str) -> bool
|
||||
"""
|
||||
Check if everybody/world has any right (read/write/execute) on a file given its path
|
||||
Check if everybody/world has any right (read/write/execute) on a file given its path.
|
||||
|
||||
:param str path: path to test
|
||||
:return: True if everybody/world has any right to the file
|
||||
:rtype: bool
|
||||
@@ -382,7 +429,8 @@ def has_world_permissions(path):
|
||||
def compute_private_key_mode(old_key, base_mode):
|
||||
# type: (str, int) -> int
|
||||
"""
|
||||
Calculate the POSIX mode to apply to a private key given the previous private key
|
||||
Calculate the POSIX mode to apply to a private key given the previous private key.
|
||||
|
||||
:param str old_key: path to the previous private key
|
||||
:param int base_mode: the minimum modes to apply to a private key
|
||||
:return: the POSIX mode to apply
|
||||
@@ -405,6 +453,7 @@ def has_same_ownership(path1, path2):
|
||||
"""
|
||||
Return True if the ownership of two files given their respective path is the same.
|
||||
On Windows, ownership is checked against owner only, since files do not have a group owner.
|
||||
|
||||
:param str path1: path to the first file
|
||||
:param str path2: path to the second file
|
||||
:return: True if both files have the same ownership, False otherwise
|
||||
@@ -430,6 +479,7 @@ def has_min_permissions(path, min_mode):
|
||||
"""
|
||||
Check if a file given its path has at least the permissions defined by the given minimal mode.
|
||||
On Windows, group permissions are ignored since files do not have a group owner.
|
||||
|
||||
:param str path: path to the file to check
|
||||
:param int min_mode: the minimal permissions expected
|
||||
:return: True if the file matches the minimal permissions expectations, False otherwise
|
||||
@@ -505,7 +555,9 @@ def _apply_win_mode(file_path, mode):
|
||||
win32security.SetFileSecurity(file_path, win32security.DACL_SECURITY_INFORMATION, security)
|
||||
|
||||
|
||||
def _generate_dacl(user_sid, mode):
|
||||
def _generate_dacl(user_sid, mode, mask=None):
|
||||
if mask:
|
||||
mode = mode & (0o777 - mask)
|
||||
analysis = _analyze_mode(mode)
|
||||
|
||||
# Get standard accounts from "well-known" sid
|
||||
|
||||
@@ -12,7 +12,7 @@ import sys
|
||||
from certbot import errors
|
||||
from certbot.compat import os
|
||||
|
||||
from acme.magic_typing import Tuple
|
||||
from acme.magic_typing import Tuple, Optional
|
||||
|
||||
try:
|
||||
from win32com.shell import shell as shellwin32
|
||||
@@ -116,8 +116,8 @@ def underscores_for_unsupported_characters_in_path(path):
|
||||
return drive + tail.replace(':', '_')
|
||||
|
||||
|
||||
def execute_command(cmd_name, shell_cmd):
|
||||
# type: (str, str) -> Tuple[str, str]
|
||||
def execute_command(cmd_name, shell_cmd, env=None):
|
||||
# type: (str, str, Optional[dict]) -> Tuple[str, str]
|
||||
"""
|
||||
Run a command:
|
||||
- on Linux command will be run by the standard shell selected with Popen(shell=True)
|
||||
@@ -125,6 +125,7 @@ def execute_command(cmd_name, shell_cmd):
|
||||
|
||||
:param str cmd_name: the user facing name of the hook being run
|
||||
:param str shell_cmd: shell command to execute
|
||||
:param dict env: environ to pass into Popen
|
||||
|
||||
:returns: `tuple` (`str` stderr, `str` stdout)
|
||||
"""
|
||||
@@ -132,11 +133,12 @@ def execute_command(cmd_name, shell_cmd):
|
||||
|
||||
if POSIX_MODE:
|
||||
cmd = subprocess.Popen(shell_cmd, shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, universal_newlines=True)
|
||||
stderr=subprocess.PIPE, universal_newlines=True,
|
||||
env=env)
|
||||
else:
|
||||
line = ['powershell.exe', '-Command', shell_cmd]
|
||||
cmd = subprocess.Popen(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
universal_newlines=True, env=env)
|
||||
|
||||
# universal_newlines causes Popen.communicate()
|
||||
# to return str objects instead of bytes in Python 3
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user