Merge branch 'master-uptsream' into apache-integration-tests

# Conflicts:
#	.travis.yml
#	tox.ini
This commit is contained in:
Adrien Ferrand 2019-09-25 19:59:54 +02:00
commit 4dddb8f060
81 changed files with 1285 additions and 421 deletions

View file

@ -6,13 +6,13 @@ coverage:
flags: linux
# Fixed target instead of auto set by #7173, can
# be removed when flags in Codecov are added back.
target: 97.5
target: 97.4
threshold: 0.1
base: auto
windows:
flags: windows
# Fixed target instead of auto set by #7173, can
# be removed when flags in Codecov are added back.
target: 97.6
target: 97.7
threshold: 0.1
base: auto

View file

@ -1,2 +1,5 @@
[run]
omit = */setup.py
[report]
omit = */setup.py

View file

@ -1,4 +1,5 @@
language: python
dist: xenial
cache:
directories:
@ -77,6 +78,9 @@ matrix:
- python: "3.7"
env: TOXENV=py37
<<: *not-on-master
- python: "3.8-dev"
env: TOXENV=py38
<<: *not-on-master
- env: TOXENV=apache_compat
<<: *not-on-master
- env: TOXENV=le_auto_xenial
@ -124,19 +128,31 @@ matrix:
<<: *extended-test-suite
- python: "2.7"
env: ACME_SERVER=boulder-v1 TOXENV=integration-certbot-oldest
dist: trusty # See py27-{acme,apache,certbot,dns,nginx}-oldest tests
# 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
<<: *extended-test-suite
- python: "2.7"
env: ACME_SERVER=boulder-v2 TOXENV=integration-certbot-oldest
dist: trusty # See py27-{acme,apache,certbot,dns,nginx}-oldest tests
# 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
<<: *extended-test-suite
- python: "2.7"
env: ACME_SERVER=boulder-v1 TOXENV=integration-nginx-oldest
dist: trusty # See py27-{acme,apache,certbot,dns,nginx}-oldest tests
# 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
<<: *extended-test-suite
- python: "2.7"
env: ACME_SERVER=boulder-v2 TOXENV=integration-nginx-oldest
dist: trusty # See py27-{acme,apache,certbot,dns,nginx}-oldest tests
# 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
<<: *extended-test-suite
- python: "3.4"
env: TOXENV=py34
@ -150,6 +166,9 @@ matrix:
- python: "3.7"
env: TOXENV=py37
<<: *extended-test-suite
- python: "3.8-dev"
env: TOXENV=py38
<<: *extended-test-suite
- python: "3.4"
env: ACME_SERVER=boulder-v1 TOXENV=integration
<<: *extended-test-suite
@ -174,6 +193,12 @@ matrix:
- python: "3.7"
env: ACME_SERVER=boulder-v2 TOXENV=integration
<<: *extended-test-suite
- python: "3.8-dev"
env: ACME_SERVER=boulder-v1 TOXENV=integration
<<: *extended-test-suite
- python: "3.8-dev"
env: ACME_SERVER=boulder-v2 TOXENV=integration
<<: *extended-test-suite
- env: TOXENV=le_auto_jessie
<<: *extended-test-suite
- env: TOXENV=le_auto_centos6

View file

@ -2,12 +2,28 @@
Certbot adheres to [Semantic Versioning](https://semver.org/).
## 0.38.0 - master
## 0.39.0 - master
### Added
* Support for Python 3.8 was added to Certbot and all of its components.
### Changed
* Don't send OCSP requests for expired certificates
### Fixed
*
More details about these changes can be found on our GitHub repo.
## 0.38.0 - 2019-09-03
### Added
* Disable session tickets for Nginx users when appropriate.
### Changed
* If Certbot fails to rollback your server configuration, the error message

View file

@ -3,7 +3,7 @@ from setuptools import find_packages
from setuptools.command.test import test as TestCommand
import sys
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
@ -73,6 +73,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View file

@ -7,6 +7,7 @@ from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-
from certbot import achallenges
from certbot import errors
from certbot.compat import filesystem
from certbot.compat import os
from certbot.tests import acme_util
@ -180,7 +181,7 @@ class ApacheHttp01Test(util.ApacheTest):
self.assertEqual(self.http.perform(), expected_response)
self.assertTrue(os.path.isdir(self.http.challenge_dir))
self._has_min_permissions(self.http.challenge_dir, 0o755)
self.assertTrue(filesystem.has_min_permissions(self.http.challenge_dir, 0o755))
self._test_challenge_conf()
for achall in achalls:
@ -218,15 +219,10 @@ class ApacheHttp01Test(util.ApacheTest):
name = os.path.join(self.http.challenge_dir, achall.chall.encode("token"))
validation = achall.validation(self.account_key)
self._has_min_permissions(name, 0o644)
self.assertTrue(filesystem.has_min_permissions(name, 0o644))
with open(name, 'rb') as f:
self.assertEqual(f.read(), validation.encode())
def _has_min_permissions(self, path, min_mode):
"""Tests the given file has at least the permissions in mode."""
st_mode = os.stat(path).st_mode
self.assertEqual(st_mode, st_mode | min_mode)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.37.0
-e .[dev]

View file

@ -4,13 +4,13 @@ from setuptools.command.test import test as TestCommand
import sys
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.37.0',
'certbot>=0.39.0.dev0',
'mock',
'python-augeas',
'setuptools',
@ -62,6 +62,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.37.2"
LE_AUTO_VERSION="0.38.0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -1134,73 +1134,76 @@ if [ "$1" = "--le-auto-phase2" ]; then
# To generate this, do (with docker and package hashin installed):
# ```
# letsencrypt-auto-source/rebuild_dependencies.py \
# letsencrypt-auto-sources/pieces/dependency-requirements.txt
# letsencrypt-auto-source/pieces/dependency-requirements.txt
# ```
# If you want to update a single dependency, run commands similar to these:
# ```
# pip install hashin
# hashin -r dependency-requirements.txt cryptography==1.5.2
# ```
ConfigArgParse==0.14.0 \
--hash=sha256:2e2efe2be3f90577aca9415e32cb629aa2ecd92078adbe27b53a03e53ff12e91
asn1crypto==0.24.0 \
--hash=sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87 \
--hash=sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49
certifi==2019.3.9 \
--hash=sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5 \
--hash=sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae
cffi==1.12.2 \
--hash=sha256:00b97afa72c233495560a0793cdc86c2571721b4271c0667addc83c417f3d90f \
--hash=sha256:0ba1b0c90f2124459f6966a10c03794082a2f3985cd699d7d63c4a8dae113e11 \
--hash=sha256:0bffb69da295a4fc3349f2ec7cbe16b8ba057b0a593a92cbe8396e535244ee9d \
--hash=sha256:21469a2b1082088d11ccd79dd84157ba42d940064abbfa59cf5f024c19cf4891 \
--hash=sha256:2e4812f7fa984bf1ab253a40f1f4391b604f7fc424a3e21f7de542a7f8f7aedf \
--hash=sha256:2eac2cdd07b9049dd4e68449b90d3ef1adc7c759463af5beb53a84f1db62e36c \
--hash=sha256:2f9089979d7456c74d21303c7851f158833d48fb265876923edcb2d0194104ed \
--hash=sha256:3dd13feff00bddb0bd2d650cdb7338f815c1789a91a6f68fdc00e5c5ed40329b \
--hash=sha256:4065c32b52f4b142f417af6f33a5024edc1336aa845b9d5a8d86071f6fcaac5a \
--hash=sha256:51a4ba1256e9003a3acf508e3b4f4661bebd015b8180cc31849da222426ef585 \
--hash=sha256:59888faac06403767c0cf8cfb3f4a777b2939b1fbd9f729299b5384f097f05ea \
--hash=sha256:59c87886640574d8b14910840327f5cd15954e26ed0bbd4e7cef95fa5aef218f \
--hash=sha256:610fc7d6db6c56a244c2701575f6851461753c60f73f2de89c79bbf1cc807f33 \
--hash=sha256:70aeadeecb281ea901bf4230c6222af0248c41044d6f57401a614ea59d96d145 \
--hash=sha256:71e1296d5e66c59cd2c0f2d72dc476d42afe02aeddc833d8e05630a0551dad7a \
--hash=sha256:8fc7a49b440ea752cfdf1d51a586fd08d395ff7a5d555dc69e84b1939f7ddee3 \
--hash=sha256:9b5c2afd2d6e3771d516045a6cfa11a8da9a60e3d128746a7fe9ab36dfe7221f \
--hash=sha256:9c759051ebcb244d9d55ee791259ddd158188d15adee3c152502d3b69005e6bd \
--hash=sha256:b4d1011fec5ec12aa7cc10c05a2f2f12dfa0adfe958e56ae38dc140614035804 \
--hash=sha256:b4f1d6332339ecc61275bebd1f7b674098a66fea11a00c84d1c58851e618dc0d \
--hash=sha256:c030cda3dc8e62b814831faa4eb93dd9a46498af8cd1d5c178c2de856972fd92 \
--hash=sha256:c2e1f2012e56d61390c0e668c20c4fb0ae667c44d6f6a2eeea5d7148dcd3df9f \
--hash=sha256:c37c77d6562074452120fc6c02ad86ec928f5710fbc435a181d69334b4de1d84 \
--hash=sha256:c8149780c60f8fd02752d0429246088c6c04e234b895c4a42e1ea9b4de8d27fb \
--hash=sha256:cbeeef1dc3c4299bd746b774f019de9e4672f7cc666c777cd5b409f0b746dac7 \
--hash=sha256:e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7 \
--hash=sha256:e21162bf941b85c0cda08224dade5def9360f53b09f9f259adb85fc7dd0e7b35 \
--hash=sha256:fb6934ef4744becbda3143d30c6604718871495a5e36c408431bf33d9c146889
certifi==2019.6.16 \
--hash=sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939 \
--hash=sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695
cffi==1.12.3 \
--hash=sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774 \
--hash=sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d \
--hash=sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90 \
--hash=sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b \
--hash=sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63 \
--hash=sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45 \
--hash=sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25 \
--hash=sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3 \
--hash=sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b \
--hash=sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647 \
--hash=sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016 \
--hash=sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4 \
--hash=sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb \
--hash=sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753 \
--hash=sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7 \
--hash=sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9 \
--hash=sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f \
--hash=sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8 \
--hash=sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f \
--hash=sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc \
--hash=sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42 \
--hash=sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3 \
--hash=sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909 \
--hash=sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45 \
--hash=sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d \
--hash=sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512 \
--hash=sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff \
--hash=sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201
chardet==3.0.4 \
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
configobj==5.0.6 \
--hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
cryptography==2.6.1 \
--hash=sha256:066f815f1fe46020877c5983a7e747ae140f517f1b09030ec098503575265ce1 \
--hash=sha256:210210d9df0afba9e000636e97810117dc55b7157c903a55716bb73e3ae07705 \
--hash=sha256:26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6 \
--hash=sha256:2afb83308dc5c5255149ff7d3fb9964f7c9ee3d59b603ec18ccf5b0a8852e2b1 \
--hash=sha256:2db34e5c45988f36f7a08a7ab2b69638994a8923853dec2d4af121f689c66dc8 \
--hash=sha256:409c4653e0f719fa78febcb71ac417076ae5e20160aec7270c91d009837b9151 \
--hash=sha256:45a4f4cf4f4e6a55c8128f8b76b4c057027b27d4c67e3fe157fa02f27e37830d \
--hash=sha256:48eab46ef38faf1031e58dfcc9c3e71756a1108f4c9c966150b605d4a1a7f659 \
--hash=sha256:6b9e0ae298ab20d371fc26e2129fd683cfc0cfde4d157c6341722de645146537 \
--hash=sha256:6c4778afe50f413707f604828c1ad1ff81fadf6c110cb669579dea7e2e98a75e \
--hash=sha256:8c33fb99025d353c9520141f8bc989c2134a1f76bac6369cea060812f5b5c2bb \
--hash=sha256:9873a1760a274b620a135054b756f9f218fa61ca030e42df31b409f0fb738b6c \
--hash=sha256:9b069768c627f3f5623b1cbd3248c5e7e92aec62f4c98827059eed7053138cc9 \
--hash=sha256:9e4ce27a507e4886efbd3c32d120db5089b906979a4debf1d5939ec01b9dd6c5 \
--hash=sha256:acb424eaca214cb08735f1a744eceb97d014de6530c1ea23beb86d9c6f13c2ad \
--hash=sha256:c8181c7d77388fe26ab8418bb088b1a1ef5fde058c6926790c8a0a3d94075a4a \
--hash=sha256:d4afbb0840f489b60f5a580a41a1b9c3622e08ecb5eec8614d4fb4cd914c4460 \
--hash=sha256:d9ed28030797c00f4bc43c86bf819266c76a5ea61d006cd4078a93ebf7da6bfd \
--hash=sha256:e603aa7bb52e4e8ed4119a58a03b60323918467ef209e6ff9db3ac382e5cf2c6
# 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' \
cryptography==2.7 \
--hash=sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c \
--hash=sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643 \
--hash=sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216 \
--hash=sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799 \
--hash=sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a \
--hash=sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9 \
--hash=sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc \
--hash=sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8 \
--hash=sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53 \
--hash=sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1 \
--hash=sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609 \
--hash=sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292 \
--hash=sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e \
--hash=sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6 \
--hash=sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed \
--hash=sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d
distro==1.4.0 \
--hash=sha256:362dde65d846d23baee4b5c058c8586f219b5a54be1cf5fc6ff55c4578392f57 \
--hash=sha256:eedf82a470ebe7d010f1872c17237c79ab04097948800029994fa458e52fb4b4
enum34==1.1.6 \
--hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
--hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
--hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
@ -1216,18 +1219,18 @@ idna==2.8 \
ipaddress==1.0.22 \
--hash=sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794 \
--hash=sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c
josepy==1.1.0 \
--hash=sha256:1309a25aac3caeff5239729c58ff9b583f7d022ffdb1553406ddfc8e5b52b76e \
--hash=sha256:fb5c62c77d26e04df29cb5ecd01b9ce69b6fcc9e521eb1ca193b7faa2afa7086
josepy==1.2.0 \
--hash=sha256:8ea15573203f28653c00f4ac0142520777b1c59d9eddd8da3f256c6ba3cac916 \
--hash=sha256:9cec9a839fe9520f0420e4f38e7219525daccce4813296627436fe444cd002d3
mock==1.3.0 \
--hash=sha256:1e247dbecc6ce057299eb7ee019ad68314bb93152e81d9a6110d35f4d5eca0f6 \
--hash=sha256:3f573a18be94de886d1191f27c168427ef693e8dcfcecf95b170577b2eb69cbb
parsedatetime==2.4 \
--hash=sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b \
--hash=sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094
pbr==5.1.3 \
--hash=sha256:8257baf496c8522437e8a6cfe0f15e00aedc6c0e0e7c9d55eeeeab31e0853843 \
--hash=sha256:8c361cc353d988e4f5b998555c88098b9d5964c2e11acf7b0d21925a66bb5824
pbr==5.4.2 \
--hash=sha256:56e52299170b9492513c64be44736d27a512fa7e606f21942160b68ce510b4bc \
--hash=sha256:9b321c204a88d8ab5082699469f52cc94c5da45c51f114113d01b3d993c24cdf
pyOpenSSL==19.0.0 \
--hash=sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200 \
--hash=sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
@ -1236,14 +1239,14 @@ pyRFC3339==1.1 \
--hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
pycparser==2.19 \
--hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
pyparsing==2.3.1 \
--hash=sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a \
--hash=sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3
pyparsing==2.4.2 \
--hash=sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80 \
--hash=sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4
python-augeas==0.5.0 \
--hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2
pytz==2018.9 \
--hash=sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9 \
--hash=sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c
pytz==2019.2 \
--hash=sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32 \
--hash=sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7
requests==2.21.0 \
--hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
--hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b
@ -1253,15 +1256,15 @@ requests-toolbelt==0.9.1 \
six==1.12.0 \
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
urllib3==1.24.2 \
--hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
--hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3
urllib3==1.24.3 \
--hash=sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4 \
--hash=sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb
zope.component==4.5 \
--hash=sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55 \
--hash=sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4
zope.deferredimport==4.3 \
--hash=sha256:2ddef5a7ecfff132a2dd796253366ecf9748a446e30f1a0b3a636aec9d9c05c5 \
--hash=sha256:4aae9cbacb2146cca58e62be0a914f0cec034d3b2d41135ea212ca8a96f4b5ec
zope.deferredimport==4.3.1 \
--hash=sha256:57b2345e7b5eef47efcd4f634ff16c93e4265de3dcf325afc7315ade48d909e1 \
--hash=sha256:9a0c211df44aa95f1c4e6d2626f90b400f56989180d3ef96032d708da3d23e0a
zope.deprecation==4.4.0 \
--hash=sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df \
--hash=sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113
@ -1309,18 +1312,18 @@ zope.interface==4.6.0 \
--hash=sha256:d788a3999014ddf416f2dc454efa4a5dbeda657c6aba031cf363741273804c6b \
--hash=sha256:eed88ae03e1ef3a75a0e96a55a99d7937ed03e53d0cffc2451c208db445a2966 \
--hash=sha256:f99451f3a579e73b5dd58b1b08d1179791d49084371d9a47baad3b22417f0317
zope.proxy==4.3.1 \
--hash=sha256:0cbcfcafaa3b5fde7ba7a7b9a2b5f09af25c9b90087ad65f9e61359fed0ca63b \
--hash=sha256:3de631dd5054a3a20b9ebff0e375f39c0565f1fb9131200d589a6a8f379214cd \
--hash=sha256:5429134d04d42262f4dac25f6dea907f6334e9a751ffc62cb1d40226fb52bdeb \
--hash=sha256:563c2454b2d0f23bca54d2e0e4d781149b7b06cb5df67e253ca3620f37202dd2 \
--hash=sha256:5bcf773345016b1461bb07f70c635b9386e5eaaa08e37d3939dcdf12d3fdbec5 \
--hash=sha256:8d84b7aef38c693874e2f2084514522bf73fd720fde0ce2a9352a51315ffa475 \
--hash=sha256:90de9473c05819b36816b6cb957097f809691836ed3142648bf62da84b4502fe \
--hash=sha256:dd592a69fe872445542a6e1acbefb8e28cbe6b4007b8f5146da917e49b155cc3 \
--hash=sha256:e7399ab865399fce322f9cefc6f2f3e4099d087ba581888a9fea1bbe1db42a08 \
--hash=sha256:e7d1c280d86d72735a420610df592aac72332194e531a8beff43a592c3a1b8eb \
--hash=sha256:e90243fee902adb0c39eceb3c69995c0f2004bc3fdb482fbf629efc656d124ed
zope.proxy==4.3.2 \
--hash=sha256:320a7619992e42142549ebf61e14ce27683b4d14b0cbc45f7c037ba64edb560c \
--hash=sha256:824d4dbabbb7deb84f25fdb96ea1eeca436a1802c3c8d323b3eb4ac9d527d41c \
--hash=sha256:8a32eb9c94908f3544da2dae3f4a9e6961d78819b88ac6b6f4a51cee2d65f4a0 \
--hash=sha256:96265fd3bc3ea646f98482e16307a69de21402eeaaaaf4b841c1161ac2f71bb0 \
--hash=sha256:ab6d6975d9c51c13cac828ff03168de21fb562b0664c59bcdc4a4b10f39a5b17 \
--hash=sha256:af10cb772391772463f65a58348e2de5ecc06693c16d2078be276dc068bcbb54 \
--hash=sha256:b8fd3a3de3f7b6452775e92af22af5977b17b69ac86a38a3ddfe870e40a0d05f \
--hash=sha256:bb7088f1bed3b8214284a5e425dc23da56f2f28e8815b7580bfed9e245b6c0b6 \
--hash=sha256:bc29b3665eac34f14c4aef5224bef045efcfb1a7d12d78c8685858de5fbf21c0 \
--hash=sha256:c39fa6a159affeae5fe31b49d9f5b12bd674fe77271a9a324408b271440c50a7 \
--hash=sha256:e946a036ac5b9f897e986ac9dc950a34cffc857d88eae6727b8434fbc4752366
# Contains the requirements for the letsencrypt package.
#
@ -1333,18 +1336,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.37.2 \
--hash=sha256:8f6f0097fb2aac64f13e5d6974781ac85a051d84a6cb3f4d79c6b75c5ea451b8 \
--hash=sha256:e454368aa8d62559c673091b511319c130c8e0ea1c4dfa314ed7bdc91dd96ef5
acme==0.37.2 \
--hash=sha256:5666ba927a9e7bf3f9ed5a268bd5acf627b5838fb409e8401f05d2aaaee188ba \
--hash=sha256:88798fae3bc692397db79c66930bd02fcaba8a6b1fba9a62f111dda42cc47f5c
certbot-apache==0.37.2 \
--hash=sha256:e3ae7057f727506ab3796095ed66ca083f4e295d06f209ab96d2a3f37dea51b9 \
--hash=sha256:4cb44d1a7c56176a84446a11412c561479ed0fed19848632e61f104dbf6a3031
certbot-nginx==0.37.2 \
--hash=sha256:a92dffdf3daca97db5d7ae2287e505110c3fa01c035b9356abb2ef9fa32e8695 \
--hash=sha256:404f7b5b7611f0dce8773739170f306e94a59b69528cb74337e7f354936ac061
certbot==0.38.0 \
--hash=sha256:618abf3ae17c2fc3cb99baa4bf000dd5e2d7875b7811f5ef1edf6ebd7a33945f \
--hash=sha256:c27712101794e3adf54f3a3067c63be5caa507a930a79865bc654b6864121c6b
acme==0.38.0 \
--hash=sha256:6231571b4a94d6d621b28bef6f6d4846b3c2ebca840f9718d3212036c3bd2af8 \
--hash=sha256:1c1e9c0826a8f72d670b0ca28b7e6392ce4781eb33222f35133705b6551885d8
certbot-apache==0.38.0 \
--hash=sha256:0b5a2c2bcc430470b5131941ebdfde0a13e28dec38918c1a4ebea5dd35ad38bc \
--hash=sha256:2d335543e0ae9292303238736907ce6b321ac49eb49fe4e0b775abdc0ba57c62
certbot-nginx==0.38.0 \
--hash=sha256:af82944e171d2e93c81438b185f8051e742c6f47f7382cb1a647b1c7ca2b53f2 \
--hash=sha256:cecd1fa3de6e19980fdb9c3b3269b15b7da71b5748ee7ae5caddcc18dbb208ac
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -2,6 +2,7 @@
# Avoid false warnings because certbot packages are not installed in the thread that executes
# the coverage: indeed, certbot is launched as a CLI from a subprocess.
disable_warnings = module-not-imported,no-data-collected
omit = **/*_test.py,**/tests/*,**/dns_common*,**/certbot_nginx/parser_obj.py
[report]
# Exclude unit tests in coverage during integration tests.

View file

@ -51,6 +51,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View file

@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
install_requires = [
'certbot',
@ -47,6 +47,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'cloudflare>=1.5.1',
'mock',
'setuptools',
@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',
@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'mock',
'python-digitalocean>=1.11',
'setuptools',
@ -44,6 +44,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -3,13 +3,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'mock',
'setuptools',
'zope.interface',
@ -55,6 +55,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',
@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,12 +2,12 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dns-lexicon>=2.1.22',
'mock',
'setuptools',
@ -41,6 +41,8 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
# 1.5 is the first version that supports oauth2client>=2.0
'google-api-python-client>=1.5',
'mock',
@ -48,6 +48,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,4 +1,4 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]
dns-lexicon==2.2.3

View file

@ -1,12 +1,12 @@
from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dns-lexicon>=2.2.3',
'mock',
'setuptools',
@ -41,6 +41,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',
@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',
@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,4 +1,4 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]
dns-lexicon==2.7.14

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
'mock',
'setuptools',
@ -42,6 +42,8 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dnspython',
'mock',
'setuptools',
@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -1,13 +1,13 @@
from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'boto3',
'mock',
'setuptools',
@ -37,6 +37,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.31.0
certbot[dev]==0.34.0
-e .[dev]

View file

@ -2,12 +2,12 @@ from setuptools import setup
from setuptools import find_packages
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0',
'certbot>=0.34.0',
'certbot>=0.39.0.dev0',
'dns-lexicon>=2.1.23',
'mock',
'setuptools',
@ -41,6 +41,8 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -1,4 +1,6 @@
"""Nginx Configuration"""
# https://github.com/PyCQA/pylint/issues/73
from distutils.version import LooseVersion # pylint: disable=no-name-in-module,import-error
import logging
import re
import socket
@ -91,8 +93,12 @@ class NginxConfigurator(common.Installer):
:param tup version: version of Nginx as a tuple (1, 4, 7)
(used mostly for unittesting)
:param tup openssl_version: version of OpenSSL linked to Nginx as a tuple (1, 4, 7)
(used mostly for unittesting)
"""
version = kwargs.pop("version", None)
openssl_version = kwargs.pop("openssl_version", None)
super(NginxConfigurator, self).__init__(*args, **kwargs)
# Verify that all directories and files exist with proper permissions
@ -115,6 +121,7 @@ class NginxConfigurator(common.Installer):
# These will be set in the prepare function
self.parser = None
self.version = version
self.openssl_version = openssl_version
self._enhance_func = {"redirect": self._enable_redirect,
"ensure-http-header": self._set_http_header,
"staple-ocsp": self._enable_ocsp_stapling}
@ -124,11 +131,33 @@ class NginxConfigurator(common.Installer):
@property
def mod_ssl_conf_src(self):
"""Full absolute path to SSL configuration file source."""
config_filename = "options-ssl-nginx.conf"
if self.version < (1, 5, 9):
config_filename = "options-ssl-nginx-old.conf"
elif self.version < (1, 13, 0):
config_filename = "options-ssl-nginx-tls12-only.conf"
# Why all this complexity? Well, we want to support Mozilla's intermediate
# recommendations. But TLS1.3 is only supported by newer versions of Nginx.
# And as for session tickets, our ideal is to turn them off across the board.
# But! Turning them off at all is only supported with new enough versions of
# Nginx. And older versions of OpenSSL have a bug that leads to browser errors
# given certain configurations. While we'd prefer to have forward secrecy, we'd
# rather fail open than error out. Unfortunately, Nginx can be compiled against
# many versions of OpenSSL. So we have to check both for the two different features,
# leading to four different combinations of options.
# For a complete history, check out https://github.com/certbot/certbot/issues/7322
use_tls13 = self.version >= (1, 13, 0)
session_tix_off = self.version >= (1, 5, 9) and self.openssl_version and\
LooseVersion(self.openssl_version) >= LooseVersion('1.0.2l')
if use_tls13:
if session_tix_off:
config_filename = "options-ssl-nginx.conf"
else:
config_filename = "options-ssl-nginx-tls13-session-tix-on.conf"
else:
if session_tix_off:
config_filename = "options-ssl-nginx-tls12-only.conf"
else:
config_filename = "options-ssl-nginx-old.conf"
return pkg_resources.resource_filename(
"certbot_nginx", os.path.join("tls_configs", config_filename))
@ -169,6 +198,9 @@ class NginxConfigurator(common.Installer):
if self.version is None:
self.version = self.get_version()
if self.openssl_version is None:
self.openssl_version = self._get_openssl_version()
self.install_ssl_options_conf(self.mod_ssl_conf, self.updated_mod_ssl_conf_digest)
self.install_ssl_dhparams()
@ -909,17 +941,14 @@ class NginxConfigurator(common.Installer):
util.make_or_verify_dir(self.config.backup_dir, core_constants.CONFIG_DIRS_MODE)
util.make_or_verify_dir(self.config.config_dir, core_constants.CONFIG_DIRS_MODE)
def get_version(self):
"""Return version of Nginx Server.
def _nginx_version(self):
"""Return results of nginx -V
Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))
:returns: version
:rtype: tuple
:returns: version text
:rtype: str
:raises .PluginError:
Unable to find Nginx version or version is unsupported
Unable to run Nginx version command
"""
try:
proc = subprocess.Popen(
@ -932,6 +961,21 @@ class NginxConfigurator(common.Installer):
logger.debug(str(error), exc_info=True)
raise errors.PluginError(
"Unable to run %s -V" % self.conf('ctl'))
return text
def get_version(self):
"""Return version of Nginx Server.
Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))
:returns: version
:rtype: tuple
:raises .PluginError:
Unable to find Nginx version or version is unsupported
"""
text = self._nginx_version()
version_regex = re.compile(r"nginx version: ([^/]+)/([0-9\.]*)", re.IGNORECASE)
version_matches = version_regex.findall(text)
@ -964,6 +1008,28 @@ class NginxConfigurator(common.Installer):
return nginx_version
def _get_openssl_version(self):
"""Return version of OpenSSL linked to Nginx.
Version is returned as string. If no version can be found, empty string is returned.
:returns: openssl_version
:rtype: str
:raises .PluginError:
Unable to run Nginx version command
"""
text = self._nginx_version()
matches = re.findall(r"running with OpenSSL ([^ ]+) ", text)
if not matches:
matches = re.findall(r"built with OpenSSL ([^ ]+) ", text)
if not matches:
logger.warning("NGINX configured with OpenSSL alternatives is not officially"
"supported by Certbot.")
return ""
return matches[0]
def more_info(self):
"""Human-readable string to help understand the module"""
return (

View file

@ -22,21 +22,6 @@ MOD_SSL_CONF_DEST = "options-ssl-nginx.conf"
UPDATED_MOD_SSL_CONF_DIGEST = ".updated-options-ssl-nginx-conf-digest.txt"
"""Name of the hash of the updated or informed mod_ssl_conf as saved in `IConfig.config_dir`."""
SSL_OPTIONS_HASHES_NEW = [
'108c4555058a087496a3893aea5d9e1cee0f20a3085d44a52dc1a66522299ac3',
'd5e021706ecdccc7090111b0ae9a29ef61523e927f020e410caf0a1fd7063981',
]
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.13.0"""
SSL_OPTIONS_HASHES_MEDIUM = [
'63e2bddebb174a05c9d8a7cf2adf72f7af04349ba59a1a925fe447f73b2f1abf',
'2901debc7ecbc10917edd9084c05464c9c5930b463677571eaf8c94bffd11ae2',
'30baca73ed9a5b0e9a69ea40e30482241d8b1a7343aa79b49dc5d7db0bf53b6c',
'02329eb19930af73c54b3632b3165d84571383b8c8c73361df940cb3894dd426',
]
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.5.9
and nginx < 1.13.0"""
ALL_SSL_OPTIONS_HASHES = [
'0f81093a1465e3d4eaa8b0c14e77b2a2e93568b0fc1351c2b87893a95f0de87c',
'9a7b32c49001fed4cff8ad24353329472a50e86ade1ef9b2b9e43566a619612e',
@ -46,7 +31,13 @@ ALL_SSL_OPTIONS_HASHES = [
'4b16fec2bcbcd8a2f3296d886f17f9953ffdcc0af54582452ca1e52f5f776f16',
'c052ffff0ad683f43bffe105f7c606b339536163490930e2632a335c8d191cc4',
'02329eb19930af73c54b3632b3165d84571383b8c8c73361df940cb3894dd426',
] + SSL_OPTIONS_HASHES_MEDIUM + SSL_OPTIONS_HASHES_NEW
'63e2bddebb174a05c9d8a7cf2adf72f7af04349ba59a1a925fe447f73b2f1abf',
'2901debc7ecbc10917edd9084c05464c9c5930b463677571eaf8c94bffd11ae2',
'30baca73ed9a5b0e9a69ea40e30482241d8b1a7343aa79b49dc5d7db0bf53b6c',
'02329eb19930af73c54b3632b3165d84571383b8c8c73361df940cb3894dd426',
'108c4555058a087496a3893aea5d9e1cee0f20a3085d44a52dc1a66522299ac3',
'd5e021706ecdccc7090111b0ae9a29ef61523e927f020e410caf0a1fd7063981',
]
"""SHA256 hashes of the contents of all versions of MOD_SSL_CONF_SRC"""
def os_constant(key):

View file

@ -394,6 +394,68 @@ class NginxConfiguratorTest(util.NginxTest):
mock_popen.side_effect = OSError("Can't find program")
self.assertRaises(errors.PluginError, self.config.get_version)
@mock.patch("certbot_nginx.configurator.subprocess.Popen")
def test_get_openssl_version(self, mock_popen):
# pylint: disable=protected-access
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with OpenSSL 1.0.2g 1 Mar 2016
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "1.0.2g")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with OpenSSL 1.0.2-beta1 1 Mar 2016
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "1.0.2-beta1")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with OpenSSL 1.0.2 1 Mar 2016
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "1.0.2")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with OpenSSL 1.0.2g 1 Mar 2016 (running with OpenSSL 1.0.2a 1 Mar 2016)
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "1.0.2a")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
built with LibreSSL 2.2.2
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "")
mock_popen().communicate.return_value = (
"", """
nginx version: nginx/1.15.5
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
TLS SNI support enabled
configure arguments:
""")
self.assertEqual(self.config._get_openssl_version(), "")
@mock.patch("certbot_nginx.configurator.subprocess.Popen")
def test_nginx_restart(self, mock_popen):
mocked = mock_popen()
@ -920,13 +982,12 @@ class InstallSslOptionsConfTest(util.NginxTest):
self._assert_current_file()
def test_prev_file_updates_to_current_old_nginx(self):
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES, SSL_OPTIONS_HASHES_NEW
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES
self.config.version = (1, 5, 8)
with mock.patch('certbot.crypto_util.sha256sum',
new=self._mock_hash_except_ssl_conf_src(ALL_SSL_OPTIONS_HASHES[0])):
self._call()
self._assert_current_file()
self.assertTrue(self._current_ssl_options_hash() not in SSL_OPTIONS_HASHES_NEW)
def test_manually_modified_current_file_does_not_update(self):
with open(self.config.mod_ssl_conf, "a") as mod_ssl_conf:
@ -987,11 +1048,13 @@ class InstallSslOptionsConfTest(util.NginxTest):
def test_nginx_version_uses_correct_config(self):
self.config.version = (1, 5, 8)
self.config.openssl_version = "1.0.2g" # shouldn't matter
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx-old.conf")
self._call()
self._assert_current_file()
self.config.version = (1, 5, 9)
self.config.openssl_version = "1.0.2l"
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx-tls12-only.conf")
self._call()
@ -999,6 +1062,12 @@ class InstallSslOptionsConfTest(util.NginxTest):
self.config.version = (1, 13, 0)
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx.conf")
self._call()
self._assert_current_file()
self.config.version = (1, 13, 0)
self.config.openssl_version = "1.0.2k"
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx-tls13-session-tix-on.conf")
class DetermineDefaultServerRootTest(certbot_test_util.ConfigTestCase):

View file

@ -54,7 +54,7 @@ def get_data_filename(filename):
def get_nginx_configurator(
config_path, config_dir, work_dir, logs_dir, version=(1, 6, 2)):
config_path, config_dir, work_dir, logs_dir, version=(1, 6, 2), openssl_version="1.0.2g"):
"""Create an Nginx Configurator with the specified options."""
backups = os.path.join(work_dir, "backups")
@ -79,7 +79,8 @@ def get_nginx_configurator(
https_port=5001,
),
name="nginx",
version=version)
version=version,
openssl_version=openssl_version)
config.prepare()
# Provide general config utility.

View file

@ -6,6 +6,7 @@
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers off;

View file

@ -0,0 +1,13 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

View file

@ -6,6 +6,7 @@
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;

View file

@ -4,7 +4,7 @@ from setuptools.command.test import test as TestCommand
import sys
version = '0.38.0.dev0'
version = '0.39.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
@ -62,6 +62,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

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

View file

@ -262,7 +262,7 @@ def human_readable_cert_info(config, cert, skip_filter_checks=False):
reasons.append('TEST_CERT')
if cert.target_expiry <= now:
reasons.append('EXPIRED')
if checker.ocsp_revoked(cert.cert, cert.chain):
elif checker.ocsp_revoked(cert):
reasons.append('REVOKED')
if reasons:

View file

@ -20,7 +20,7 @@ except ImportError:
else:
POSIX_MODE = False
from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-module
from acme.magic_typing import List, Union, Tuple # pylint: disable=unused-import, no-name-in-module
def chmod(file_path, mode):
@ -264,6 +264,7 @@ def replace(src, dst):
def realpath(file_path):
# type: (str) -> str
"""
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.
@ -300,10 +301,11 @@ def realpath(file_path):
# requires to be run under a privileged shell, so the user will always benefit
# from the highest (privileged one) set of permissions on a given file.
def is_executable(path):
# type: (str) -> bool
"""
Is path an executable file?
:param str path: path to test
:returns: True if path is an executable file
:return: True if path is an executable file
:rtype: bool
"""
if POSIX_MODE:
@ -312,6 +314,118 @@ def is_executable(path):
return _win_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
:param str path: path to test
:return: True if everybody/world has any right to the file
:rtype: bool
"""
if POSIX_MODE:
return bool(stat.S_IMODE(os.stat(path).st_mode) & stat.S_IRWXO)
security = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = security.GetSecurityDescriptorDacl()
return bool(dacl.GetEffectiveRightsFromAcl({
'TrusteeForm': win32security.TRUSTEE_IS_SID,
'TrusteeType': win32security.TRUSTEE_IS_USER,
'Identifier': win32security.ConvertStringSidToSid('S-1-1-0'),
}))
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
: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
:rtype: int
"""
if POSIX_MODE:
# On Linux, we keep read/write/execute permissions
# for group and read permissions for everybody.
old_mode = (stat.S_IMODE(os.stat(old_key).st_mode) &
(stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH))
return base_mode | old_mode
# On Windows, the mode returned by os.stat is not reliable,
# so we do not keep any permission from the previous private key.
return base_mode
def has_same_ownership(path1, path2):
# type: (str, str) -> bool
"""
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
:rtype: bool
"""
if POSIX_MODE:
stats1 = os.stat(path1)
stats2 = os.stat(path2)
return (stats1.st_uid, stats1.st_gid) == (stats2.st_uid, stats2.st_gid)
security1 = win32security.GetFileSecurity(path1, win32security.OWNER_SECURITY_INFORMATION)
user1 = security1.GetSecurityDescriptorOwner()
security2 = win32security.GetFileSecurity(path2, win32security.OWNER_SECURITY_INFORMATION)
user2 = security2.GetSecurityDescriptorOwner()
return user1 == user2
def has_min_permissions(path, min_mode):
# type: (str, int) -> bool
"""
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
:rtype: bool
"""
if POSIX_MODE:
st_mode = os.stat(path).st_mode
return st_mode == st_mode | min_mode
# Resolve symlinks, to get a consistent result with os.stat on Linux,
# that follows symlinks by default.
path = realpath(path)
# Get owner sid of the file
security = win32security.GetFileSecurity(
path, win32security.OWNER_SECURITY_INFORMATION | win32security.DACL_SECURITY_INFORMATION)
user = security.GetSecurityDescriptorOwner()
dacl = security.GetSecurityDescriptorDacl()
min_dacl = _generate_dacl(user, min_mode)
for index in range(min_dacl.GetAceCount()):
min_ace = min_dacl.GetAce(index)
# On a given ACE, index 0 is the ACE type, 1 is the permission mask, and 2 is the SID.
# See: http://timgolden.me.uk/pywin32-docs/PyACL__GetAce_meth.html
mask = min_ace[1]
user = min_ace[2]
effective_mask = dacl.GetEffectiveRightsFromAcl({
'TrusteeForm': win32security.TRUSTEE_IS_SID,
'TrusteeType': win32security.TRUSTEE_IS_USER,
'Identifier': user,
})
if effective_mask != effective_mask | mask:
return False
return True
def _win_is_executable(path):
if not os.path.isfile(path):
return False
@ -472,8 +586,8 @@ def _compare_dacls(dacl1, dacl2):
This method compare the two given DACLs to check if they are identical.
Identical means here that they contains the same set of ACEs in the same order.
"""
return ([dacl1.GetAce(index) for index in range(0, dacl1.GetAceCount())] ==
[dacl2.GetAce(index) for index in range(0, dacl2.GetAceCount())])
return ([dacl1.GetAce(index) for index in range(dacl1.GetAceCount())] ==
[dacl2.GetAce(index) for index in range(dacl2.GetAceCount())])
def _get_current_user():

View file

@ -5,7 +5,6 @@ particular category.
from __future__ import absolute_import
import select
import stat
import sys
try:
@ -18,18 +17,6 @@ from certbot import errors
from certbot.compat import os
# MASK_FOR_PRIVATE_KEY_PERMISSIONS defines what are the permissions flags to keep
# when transferring the permissions from an old private key to a new one.
if POSIX_MODE:
# On Linux, we keep read/write/execute permissions
# for group and read permissions for everybody.
MASK_FOR_PRIVATE_KEY_PERMISSIONS = stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH
else:
# On Windows, the mode returned by os.stat is not reliable,
# so we do not keep any permission from the previous private key.
MASK_FOR_PRIVATE_KEY_PERMISSIONS = 0
# For Linux: define OS specific standard binary directories
STANDARD_BINARY_DIRS = ["/usr/sbin", "/usr/local/bin", "/usr/local/sbin"] if POSIX_MODE else []

View file

@ -116,3 +116,21 @@ def access(*unused_args, **unused_kwargs):
raise RuntimeError('Usage of os.access() is forbidden. '
'Use certbot.compat.filesystem.check_mode() or '
'certbot.compat.filesystem.is_executable() instead.')
# On Windows os.stat call result is inconsistent, with a lot of flags that are not set or
# meaningless. We need to use specialized functions from the certbot.compat.filesystem module.
def stat(*unused_args, **unused_kwargs):
"""Method os.stat() is forbidden"""
raise RuntimeError('Usage of os.stat() is forbidden. '
'Use certbot.compat.filesystem functions instead '
'(eg. has_min_permissions, has_same_ownership).')
# Method os.fstat has the same problem than os.stat, since it is the same function,
# but accepting a file descriptor instead of a path.
def fstat(*unused_args, **unused_kwargs):
"""Method os.stat() is forbidden"""
raise RuntimeError('Usage of os.fstat() is forbidden. '
'Use certbot.compat.filesystem functions instead '
'(eg. has_min_permissions, has_same_ownership).')

View file

@ -167,14 +167,18 @@ class _UnixLockMechanism(_BaseLockMechanism):
:returns: True if the lock was successfully acquired
:rtype: bool
"""
# Normally os module should not be imported in certbot codebase except in certbot.compat
# for the sake of compatibility over Windows and Linux.
# We make an exception here, since _lock_success is private and called only on Linux.
from os import stat, fstat # pylint: disable=os-module-forbidden
try:
stat1 = os.stat(self._path)
stat1 = stat(self._path)
except OSError as err:
if err.errno == errno.ENOENT:
return False
raise
stat2 = os.fstat(fd)
stat2 = fstat(fd)
# If our locked file descriptor and the file on disk refer to
# the same device and inode, they're the same file.
return stat1.st_dev == stat2.st_dev and stat1.st_ino == stat2.st_ino

View file

@ -16,11 +16,13 @@ from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes # type: ignore
from cryptography.exceptions import UnsupportedAlgorithm, InvalidSignature
import pytz
import requests
from acme.magic_typing import Optional, Tuple # pylint: disable=unused-import, no-name-in-module
from certbot import crypto_util
from certbot import errors
from certbot.storage import RenewableCert # pylint: disable=unused-import
from certbot import util
logger = logging.getLogger(__name__)
@ -48,21 +50,29 @@ class RevocationChecker(object):
else:
self.host_args = lambda host: ["Host", host]
def ocsp_revoked(self, cert_path, chain_path):
# type: (str, str) -> bool
def ocsp_revoked(self, cert):
# type: (RenewableCert) -> bool
"""Get revoked status for a particular cert version.
.. todo:: Make this a non-blocking call
:param str cert_path: Path to certificate
:param str chain_path: Path to intermediate cert
:returns: True if revoked; False if valid or the check failed
:param `.storage.RenewableCert` cert: Certificate object
:returns: True if revoked; False if valid or the check failed or cert is expired.
:rtype: bool
"""
cert_path, chain_path = cert.cert, cert.chain
if self.broken:
return False
# Let's Encrypt doesn't update OCSP for expired certificates,
# so don't check OCSP if the cert is expired.
# https://github.com/certbot/certbot/issues/7152
now = pytz.UTC.fromutc(datetime.utcnow())
if cert.target_expiry <= now:
return False
url, host = _determine_ocsp_server(cert_path)
if not host or not url:
return False

View file

@ -2,7 +2,6 @@
import abc
import logging
import stat
from time import sleep
import configobj
@ -12,6 +11,7 @@ from acme import challenges
from certbot import errors
from certbot import interfaces
from certbot.compat import filesystem
from certbot.compat import os
from certbot.display import ops
from certbot.display import util as display_util
@ -312,8 +312,7 @@ def validate_file_permissions(filename):
validate_file(filename)
permissions = stat.S_IMODE(os.stat(filename).st_mode)
if permissions & stat.S_IRWXO:
if filesystem.has_world_permissions(filename):
logger.warning('Unsafe permissions on credentials configuration file: %s', filename)

View file

@ -7,14 +7,15 @@ import unittest
import mock
from certbot import errors
from certbot import util
from certbot.compat import os
from certbot.display import util as display_util
from certbot.plugins import dns_common
from certbot.plugins import dns_test_common
from certbot.tests import util
from certbot.tests import util as test_util
class DNSAuthenticatorTest(util.TempDirTestCase, dns_test_common.BaseAuthenticatorTest):
class DNSAuthenticatorTest(test_util.TempDirTestCase, dns_test_common.BaseAuthenticatorTest):
# pylint: disable=protected-access
class _FakeDNSAuthenticator(dns_common.DNSAuthenticator):
@ -50,7 +51,7 @@ class DNSAuthenticatorTest(util.TempDirTestCase, dns_test_common.BaseAuthenticat
self.auth._cleanup.assert_called_once_with(dns_test_common.DOMAIN, mock.ANY, mock.ANY)
@util.patch_get_utility()
@test_util.patch_get_utility()
def test_prompt(self, mock_get_utility):
mock_display = mock_get_utility()
mock_display.input.side_effect = ((display_util.OK, "",),
@ -59,14 +60,14 @@ class DNSAuthenticatorTest(util.TempDirTestCase, dns_test_common.BaseAuthenticat
self.auth._configure("other_key", "")
self.assertEqual(self.auth.config.fake_other_key, "value")
@util.patch_get_utility()
@test_util.patch_get_utility()
def test_prompt_canceled(self, mock_get_utility):
mock_display = mock_get_utility()
mock_display.input.side_effect = ((display_util.CANCEL, "c",),)
self.assertRaises(errors.PluginError, self.auth._configure, "other_key", "")
@util.patch_get_utility()
@test_util.patch_get_utility()
def test_prompt_file(self, mock_get_utility):
path = os.path.join(self.tempdir, 'file.ini')
open(path, "wb").close()
@ -80,7 +81,7 @@ class DNSAuthenticatorTest(util.TempDirTestCase, dns_test_common.BaseAuthenticat
self.auth._configure_file("file_path", "")
self.assertEqual(self.auth.config.fake_file_path, path)
@util.patch_get_utility()
@test_util.patch_get_utility()
def test_prompt_file_canceled(self, mock_get_utility):
mock_display = mock_get_utility()
mock_display.directory_select.side_effect = ((display_util.CANCEL, "c",),)
@ -96,7 +97,7 @@ class DNSAuthenticatorTest(util.TempDirTestCase, dns_test_common.BaseAuthenticat
self.assertEqual(credentials.conf("test"), "value")
@util.patch_get_utility()
@test_util.patch_get_utility()
def test_prompt_credentials(self, mock_get_utility):
bad_path = os.path.join(self.tempdir, 'bad-file.ini')
dns_test_common.write({"fake_other": "other_value"}, bad_path)
@ -116,7 +117,7 @@ class DNSAuthenticatorTest(util.TempDirTestCase, dns_test_common.BaseAuthenticat
self.assertEqual(credentials.conf("test"), "value")
class CredentialsConfigurationTest(util.TempDirTestCase):
class CredentialsConfigurationTest(test_util.TempDirTestCase):
class _MockLoggingHandler(logging.Handler):
messages = None
@ -150,14 +151,14 @@ class CredentialsConfigurationTest(util.TempDirTestCase):
dns_common.logger.addHandler(log)
path = os.path.join(self.tempdir, 'too-permissive-file.ini')
open(path, "wb").close()
util.safe_open(path, "wb", 0o744).close()
dns_common.CredentialsConfiguration(path)
self.assertEqual(1, len([_ for _ in log.messages['warning'] if _.startswith("Unsafe")]))
class CredentialsConfigurationRequireTest(util.TempDirTestCase):
class CredentialsConfigurationRequireTest(test_util.TempDirTestCase):
def setUp(self):
super(CredentialsConfigurationRequireTest, self).setUp()

View file

@ -34,7 +34,13 @@ class AuthenticatorTest(unittest.TestCase):
def setUp(self):
from certbot.plugins.webroot import Authenticator
self.path = tempfile.mkdtemp()
# On Linux directories created by tempfile.mkdtemp inherit their permissions from their
# parent directory. So the actual permissions are inconsistent over various tests env.
# To circumvent this, a dedicated sub-workspace is created under the workspace, using
# filesystem.mkdir to get consistent permissions.
self.workspace = tempfile.mkdtemp()
self.path = os.path.join(self.workspace, 'webroot')
filesystem.mkdir(self.path)
self.partial_root_challenge_path = os.path.join(
self.path, ".well-known")
self.root_challenge_path = os.path.join(
@ -170,17 +176,12 @@ class AuthenticatorTest(unittest.TestCase):
self.assertTrue(filesystem.check_mode(self.validation_path, 0o644))
# Check permissions of the directories
for dirpath, dirnames, _ in os.walk(self.path):
for directory in dirnames:
full_path = os.path.join(dirpath, directory)
self.assertTrue(filesystem.check_mode(full_path, 0o755))
parent_gid = os.stat(self.path).st_gid
parent_uid = os.stat(self.path).st_uid
self.assertEqual(os.stat(self.validation_path).st_gid, parent_gid)
self.assertEqual(os.stat(self.validation_path).st_uid, parent_uid)
self.assertTrue(filesystem.has_same_ownership(self.validation_path, self.path))
def test_perform_cleanup(self):
self.auth.prepare()

View file

@ -18,7 +18,6 @@ from certbot import crypto_util
from certbot import error_handler
from certbot import errors
from certbot import util
from certbot.compat import misc
from certbot.compat import os
from certbot.compat import filesystem
from certbot.plugins import common as plugins_common
@ -1107,9 +1106,7 @@ class RenewableCert(object):
f.write(new_privkey)
# Preserve gid and (mode & MASK_FOR_PRIVATE_KEY_PERMISSIONS)
# from previous privkey in this lineage.
old_mode = (stat.S_IMODE(os.stat(old_privkey).st_mode) &
misc.MASK_FOR_PRIVATE_KEY_PERMISSIONS)
mode = BASE_PRIVKEY_MODE | old_mode
mode = filesystem.compute_private_key_mode(old_privkey, BASE_PRIVKEY_MODE)
filesystem.copy_ownership_and_apply_mode(
old_privkey, target["privkey"], mode, copy_user=False, copy_group=True)

View file

@ -150,6 +150,24 @@ class WindowsChmodTests(TempDirTestCase):
self.assertEqual(security_dacl.GetSecurityDescriptorDacl().GetAceCount(), 2)
class ComputePrivateKeyModeTest(TempDirTestCase):
def setUp(self):
super(ComputePrivateKeyModeTest, self).setUp()
self.probe_path = _create_probe(self.tempdir)
def test_compute_private_key_mode(self):
filesystem.chmod(self.probe_path, 0o777)
new_mode = filesystem.compute_private_key_mode(self.probe_path, 0o600)
if POSIX_MODE:
# On Linux RWX permissions for group and R permission for world
# are persisted from the existing moe
self.assertEqual(new_mode, 0o674)
else:
# On Windows no permission is persisted
self.assertEqual(new_mode, 0o600)
@unittest.skipIf(POSIX_MODE, reason='Tests specific to Windows security')
class WindowsOpenTest(TempDirTestCase):
def test_new_file_correct_permissions(self):
@ -262,14 +280,14 @@ class WindowsMkdirTests(test_util.TempDirTestCase):
self.assertEqual(original_mkdir, std_os.mkdir)
class CopyOwnershipTest(test_util.TempDirTestCase):
"""Tests about replacement of chown: copy_ownership_and_apply_mode"""
class OwnershipTest(test_util.TempDirTestCase):
"""Tests about copy_ownership_and_apply_mode and has_same_ownership"""
def setUp(self):
super(CopyOwnershipTest, self).setUp()
super(OwnershipTest, self).setUp()
self.probe_path = _create_probe(self.tempdir)
@unittest.skipIf(POSIX_MODE, reason='Test specific to Windows security')
def test_windows(self):
def test_copy_ownership_windows(self):
system = win32security.ConvertStringSidToSid(SYSTEM_SID)
security = win32security.SECURITY_ATTRIBUTES().SECURITY_DESCRIPTOR
security.SetSecurityDescriptorOwner(system, False)
@ -295,7 +313,7 @@ class CopyOwnershipTest(test_util.TempDirTestCase):
if dacl.GetAce(index)[2] == everybody])
@unittest.skipUnless(POSIX_MODE, reason='Test specific to Linux security')
def test_linux(self):
def test_copy_ownership_linux(self):
with mock.patch('os.chown') as mock_chown:
with mock.patch('os.chmod') as mock_chmod:
with mock.patch('os.stat') as mock_stat:
@ -307,8 +325,18 @@ class CopyOwnershipTest(test_util.TempDirTestCase):
mock_chown.assert_called_once_with(self.probe_path, 50, 51)
mock_chmod.assert_called_once_with(self.probe_path, 0o700)
def test_has_same_ownership(self):
path1 = os.path.join(self.tempdir, 'test1')
path2 = os.path.join(self.tempdir, 'test2')
util.safe_open(path1, 'w').close()
util.safe_open(path2, 'w').close()
self.assertTrue(filesystem.has_same_ownership(path1, path2))
class CheckPermissionsTest(test_util.TempDirTestCase):
"""Tests relative to functions that check modes."""
def setUp(self):
super(CheckPermissionsTest, self).setUp()
self.probe_path = _create_probe(self.tempdir)
@ -353,6 +381,23 @@ class CheckPermissionsTest(test_util.TempDirTestCase):
mock_owner.return_value = False
self.assertFalse(filesystem.check_permissions(self.probe_path, 0o744))
def test_check_min_permissions(self):
filesystem.chmod(self.probe_path, 0o744)
self.assertTrue(filesystem.has_min_permissions(self.probe_path, 0o744))
filesystem.chmod(self.probe_path, 0o700)
self.assertFalse(filesystem.has_min_permissions(self.probe_path, 0o744))
filesystem.chmod(self.probe_path, 0o741)
self.assertFalse(filesystem.has_min_permissions(self.probe_path, 0o744))
def test_is_world_reachable(self):
filesystem.chmod(self.probe_path, 0o744)
self.assertTrue(filesystem.has_world_permissions(self.probe_path))
filesystem.chmod(self.probe_path, 0o700)
self.assertFalse(filesystem.has_world_permissions(self.probe_path))
class OsReplaceTest(test_util.TempDirTestCase):
"""Test to ensure consistent behavior of rename method"""

View file

@ -8,8 +8,8 @@ class OsTest(unittest.TestCase):
"""Unit tests for os module."""
def test_forbidden_methods(self):
# Checks for os module
for method in ['chmod', 'chown', 'open', 'mkdir',
'makedirs', 'rename', 'replace', 'access']:
for method in ['chmod', 'chown', 'open', 'mkdir', 'makedirs', 'rename',
'replace', 'access', 'stat', 'fstat']:
self.assertRaises(RuntimeError, getattr(os, method))
# Checks for os.path module
for method in ['realpath']:

View file

@ -82,7 +82,10 @@ class LockFileTest(test_util.TempDirTestCase):
'Race conditions on lock are specific to the non-blocking file access approach on Linux.')
def test_race(self):
should_delete = [True, False]
stat = os.stat
# Normally os module should not be imported in certbot codebase except in certbot.compat
# for the sake of compatibility over Windows and Linux.
# We make an exception here, since test_race is a test function called only on Linux.
from os import stat # pylint: disable=os-module-forbidden
def delete_and_stat(path):
"""Wrap os.stat and maybe delete the file first."""
@ -90,7 +93,7 @@ class LockFileTest(test_util.TempDirTestCase):
os.remove(path)
return stat(path)
with mock.patch('certbot.lock.os.stat') as mock_stat:
with mock.patch('certbot.lock.filesystem.os.stat') as mock_stat:
mock_stat.side_effect = delete_and_stat
self._call(self.lock_path)
self.assertFalse(should_delete)
@ -117,7 +120,7 @@ class LockFileTest(test_util.TempDirTestCase):
def test_unexpected_os_err(self):
if POSIX_MODE:
mock_function = 'certbot.lock.os.stat'
mock_function = 'certbot.lock.filesystem.os.stat'
else:
mock_function = 'certbot.lock.msvcrt.locking'
# The only expected errno are ENOENT and EACCES in lock module.

View file

@ -16,6 +16,7 @@ try:
except (ImportError, AttributeError): # pragma: no cover
ocsp_lib = None # type: ignore
import mock
import pytz
from certbot import errors
from certbot.tests import util as test_util
@ -72,21 +73,34 @@ class OCSPTestOpenSSL(unittest.TestCase):
@mock.patch('certbot.ocsp._determine_ocsp_server')
@mock.patch('certbot.util.run_script')
def test_ocsp_revoked(self, mock_run, mock_determine):
now = pytz.UTC.fromutc(datetime.utcnow())
cert_obj = mock.MagicMock()
cert_obj.cert = "x"
cert_obj.chain = "y"
cert_obj.target_expiry = now + timedelta(hours=2)
self.checker.broken = True
mock_determine.return_value = ("", "")
self.assertEqual(self.checker.ocsp_revoked("x", "y"), False)
self.assertEqual(self.checker.ocsp_revoked(cert_obj), False)
self.checker.broken = False
mock_run.return_value = tuple(openssl_happy[1:])
self.assertEqual(self.checker.ocsp_revoked("x", "y"), False)
self.assertEqual(self.checker.ocsp_revoked(cert_obj), False)
self.assertEqual(mock_run.call_count, 0)
mock_determine.return_value = ("http://x.co", "x.co")
self.assertEqual(self.checker.ocsp_revoked("blah.pem", "chain.pem"), False)
self.assertEqual(self.checker.ocsp_revoked(cert_obj), False)
mock_run.side_effect = errors.SubprocessError("Unable to load certificate launcher")
self.assertEqual(self.checker.ocsp_revoked("x", "y"), False)
self.assertEqual(self.checker.ocsp_revoked(cert_obj), False)
self.assertEqual(mock_run.call_count, 2)
# cert expired
cert_obj.target_expiry = now
mock_determine.return_value = ("", "")
count_before = mock_determine.call_count
self.assertEqual(self.checker.ocsp_revoked(cert_obj), False)
self.assertEqual(mock_determine.call_count, count_before)
def test_determine_ocsp_server(self):
cert_path = test_util.vector_path('ocsp_certificate.pem')
@ -131,18 +145,23 @@ class OSCPTestCryptography(unittest.TestCase):
self.checker = ocsp.RevocationChecker()
self.cert_path = test_util.vector_path('ocsp_certificate.pem')
self.chain_path = test_util.vector_path('ocsp_issuer_certificate.pem')
self.cert_obj = mock.MagicMock()
self.cert_obj.cert = self.cert_path
self.cert_obj.chain = self.chain_path
now = pytz.UTC.fromutc(datetime.utcnow())
self.cert_obj.target_expiry = now + timedelta(hours=2)
@mock.patch('certbot.ocsp._determine_ocsp_server')
@mock.patch('certbot.ocsp._check_ocsp_cryptography')
def test_ensure_cryptography_toggled(self, mock_revoke, mock_determine):
mock_determine.return_value = ('http://example.com', 'example.com')
self.checker.ocsp_revoked(self.cert_path, self.chain_path)
self.checker.ocsp_revoked(self.cert_obj)
mock_revoke.assert_called_once_with(self.cert_path, self.chain_path, 'http://example.com')
def test_revoke(self):
with _ocsp_mock(ocsp_lib.OCSPCertStatus.REVOKED, ocsp_lib.OCSPResponseStatus.SUCCESSFUL):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertTrue(revoked)
def test_responder_is_issuer(self):
@ -152,7 +171,7 @@ class OSCPTestCryptography(unittest.TestCase):
with _ocsp_mock(ocsp_lib.OCSPCertStatus.REVOKED,
ocsp_lib.OCSPResponseStatus.SUCCESSFUL) as mocks:
mocks['mock_response'].return_value.responder_name = issuer.subject
self.checker.ocsp_revoked(self.cert_path, self.chain_path)
self.checker.ocsp_revoked(self.cert_obj)
# Here responder and issuer are the same. So only the signature of the OCSP
# response is checked (using the issuer/responder public key).
self.assertEqual(mocks['mock_check'].call_count, 1)
@ -167,7 +186,7 @@ class OSCPTestCryptography(unittest.TestCase):
with _ocsp_mock(ocsp_lib.OCSPCertStatus.REVOKED,
ocsp_lib.OCSPResponseStatus.SUCCESSFUL) as mocks:
self.checker.ocsp_revoked(self.cert_path, self.chain_path)
self.checker.ocsp_revoked(self.cert_obj)
# Here responder and issuer are not the same. Two signatures will be checked then,
# first to verify the responder cert (using the issuer public key), second to
# to verify the OCSP response itself (using the responder public key).
@ -181,17 +200,17 @@ class OSCPTestCryptography(unittest.TestCase):
# Server return an invalid HTTP response
with _ocsp_mock(ocsp_lib.OCSPCertStatus.UNKNOWN, ocsp_lib.OCSPResponseStatus.SUCCESSFUL,
http_status_code=400):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
# OCSP response in invalid
with _ocsp_mock(ocsp_lib.OCSPCertStatus.UNKNOWN, ocsp_lib.OCSPResponseStatus.UNAUTHORIZED):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
# OCSP response is valid, but certificate status is unknown
with _ocsp_mock(ocsp_lib.OCSPCertStatus.UNKNOWN, ocsp_lib.OCSPResponseStatus.SUCCESSFUL):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
# The OCSP response says that the certificate is revoked, but certificate
@ -200,32 +219,32 @@ class OSCPTestCryptography(unittest.TestCase):
with mock.patch('cryptography.x509.Extensions.get_extension_for_class',
side_effect=x509.ExtensionNotFound(
'Not found', x509.AuthorityInformationAccessOID.OCSP)):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
# OCSP response uses an unsupported signature.
with _ocsp_mock(ocsp_lib.OCSPCertStatus.REVOKED, ocsp_lib.OCSPResponseStatus.SUCCESSFUL,
check_signature_side_effect=UnsupportedAlgorithm('foo')):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
# OSCP signature response is invalid.
with _ocsp_mock(ocsp_lib.OCSPCertStatus.REVOKED, ocsp_lib.OCSPResponseStatus.SUCCESSFUL,
check_signature_side_effect=InvalidSignature('foo')):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
# Assertion error on OCSP response validity
with _ocsp_mock(ocsp_lib.OCSPCertStatus.REVOKED, ocsp_lib.OCSPResponseStatus.SUCCESSFUL,
check_signature_side_effect=AssertionError('foo')):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
# No responder cert in OCSP response
with _ocsp_mock(ocsp_lib.OCSPCertStatus.REVOKED,
ocsp_lib.OCSPResponseStatus.SUCCESSFUL) as mocks:
mocks['mock_response'].return_value.certificates = []
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
# Responder cert is not signed by certificate issuer
@ -234,7 +253,7 @@ class OSCPTestCryptography(unittest.TestCase):
cert = mocks['mock_response'].return_value.certificates[0]
mocks['mock_response'].return_value.certificates[0] = mock.Mock(
issuer='fake', subject=cert.subject)
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)
with _ocsp_mock(ocsp_lib.OCSPCertStatus.REVOKED, ocsp_lib.OCSPResponseStatus.SUCCESSFUL):
@ -245,7 +264,7 @@ class OSCPTestCryptography(unittest.TestCase):
with mock.patch('cryptography.x509.Extensions.get_extension_for_class',
side_effect=x509.ExtensionNotFound(
'Not found', x509.AuthorityInformationAccessOID.OCSP)):
revoked = self.checker.ocsp_revoked(self.cert_path, self.chain_path)
revoked = self.checker.ocsp_revoked(self.cert_obj)
self.assertFalse(revoked)

View file

@ -113,7 +113,7 @@ optional arguments:
case, and to know when to deprecate support for past
Python versions and flags. If you wish to hide this
information from the Let's Encrypt server, set this to
"". (default: CertbotACMEClient/0.37.2
"". (default: CertbotACMEClient/0.38.0
(certbot(-auto); OS_NAME OS_VERSION) Authenticator/XXX
Installer/YYY (SUBCOMMAND; flags: FLAGS)
Py/major.minor.patchlevel). The flags encoded in the

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.37.2"
LE_AUTO_VERSION="0.38.0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -1134,73 +1134,76 @@ if [ "$1" = "--le-auto-phase2" ]; then
# To generate this, do (with docker and package hashin installed):
# ```
# letsencrypt-auto-source/rebuild_dependencies.py \
# letsencrypt-auto-sources/pieces/dependency-requirements.txt
# letsencrypt-auto-source/pieces/dependency-requirements.txt
# ```
# If you want to update a single dependency, run commands similar to these:
# ```
# pip install hashin
# hashin -r dependency-requirements.txt cryptography==1.5.2
# ```
ConfigArgParse==0.14.0 \
--hash=sha256:2e2efe2be3f90577aca9415e32cb629aa2ecd92078adbe27b53a03e53ff12e91
asn1crypto==0.24.0 \
--hash=sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87 \
--hash=sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49
certifi==2019.3.9 \
--hash=sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5 \
--hash=sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae
cffi==1.12.2 \
--hash=sha256:00b97afa72c233495560a0793cdc86c2571721b4271c0667addc83c417f3d90f \
--hash=sha256:0ba1b0c90f2124459f6966a10c03794082a2f3985cd699d7d63c4a8dae113e11 \
--hash=sha256:0bffb69da295a4fc3349f2ec7cbe16b8ba057b0a593a92cbe8396e535244ee9d \
--hash=sha256:21469a2b1082088d11ccd79dd84157ba42d940064abbfa59cf5f024c19cf4891 \
--hash=sha256:2e4812f7fa984bf1ab253a40f1f4391b604f7fc424a3e21f7de542a7f8f7aedf \
--hash=sha256:2eac2cdd07b9049dd4e68449b90d3ef1adc7c759463af5beb53a84f1db62e36c \
--hash=sha256:2f9089979d7456c74d21303c7851f158833d48fb265876923edcb2d0194104ed \
--hash=sha256:3dd13feff00bddb0bd2d650cdb7338f815c1789a91a6f68fdc00e5c5ed40329b \
--hash=sha256:4065c32b52f4b142f417af6f33a5024edc1336aa845b9d5a8d86071f6fcaac5a \
--hash=sha256:51a4ba1256e9003a3acf508e3b4f4661bebd015b8180cc31849da222426ef585 \
--hash=sha256:59888faac06403767c0cf8cfb3f4a777b2939b1fbd9f729299b5384f097f05ea \
--hash=sha256:59c87886640574d8b14910840327f5cd15954e26ed0bbd4e7cef95fa5aef218f \
--hash=sha256:610fc7d6db6c56a244c2701575f6851461753c60f73f2de89c79bbf1cc807f33 \
--hash=sha256:70aeadeecb281ea901bf4230c6222af0248c41044d6f57401a614ea59d96d145 \
--hash=sha256:71e1296d5e66c59cd2c0f2d72dc476d42afe02aeddc833d8e05630a0551dad7a \
--hash=sha256:8fc7a49b440ea752cfdf1d51a586fd08d395ff7a5d555dc69e84b1939f7ddee3 \
--hash=sha256:9b5c2afd2d6e3771d516045a6cfa11a8da9a60e3d128746a7fe9ab36dfe7221f \
--hash=sha256:9c759051ebcb244d9d55ee791259ddd158188d15adee3c152502d3b69005e6bd \
--hash=sha256:b4d1011fec5ec12aa7cc10c05a2f2f12dfa0adfe958e56ae38dc140614035804 \
--hash=sha256:b4f1d6332339ecc61275bebd1f7b674098a66fea11a00c84d1c58851e618dc0d \
--hash=sha256:c030cda3dc8e62b814831faa4eb93dd9a46498af8cd1d5c178c2de856972fd92 \
--hash=sha256:c2e1f2012e56d61390c0e668c20c4fb0ae667c44d6f6a2eeea5d7148dcd3df9f \
--hash=sha256:c37c77d6562074452120fc6c02ad86ec928f5710fbc435a181d69334b4de1d84 \
--hash=sha256:c8149780c60f8fd02752d0429246088c6c04e234b895c4a42e1ea9b4de8d27fb \
--hash=sha256:cbeeef1dc3c4299bd746b774f019de9e4672f7cc666c777cd5b409f0b746dac7 \
--hash=sha256:e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7 \
--hash=sha256:e21162bf941b85c0cda08224dade5def9360f53b09f9f259adb85fc7dd0e7b35 \
--hash=sha256:fb6934ef4744becbda3143d30c6604718871495a5e36c408431bf33d9c146889
certifi==2019.6.16 \
--hash=sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939 \
--hash=sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695
cffi==1.12.3 \
--hash=sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774 \
--hash=sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d \
--hash=sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90 \
--hash=sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b \
--hash=sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63 \
--hash=sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45 \
--hash=sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25 \
--hash=sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3 \
--hash=sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b \
--hash=sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647 \
--hash=sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016 \
--hash=sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4 \
--hash=sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb \
--hash=sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753 \
--hash=sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7 \
--hash=sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9 \
--hash=sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f \
--hash=sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8 \
--hash=sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f \
--hash=sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc \
--hash=sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42 \
--hash=sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3 \
--hash=sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909 \
--hash=sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45 \
--hash=sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d \
--hash=sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512 \
--hash=sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff \
--hash=sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201
chardet==3.0.4 \
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
configobj==5.0.6 \
--hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
cryptography==2.6.1 \
--hash=sha256:066f815f1fe46020877c5983a7e747ae140f517f1b09030ec098503575265ce1 \
--hash=sha256:210210d9df0afba9e000636e97810117dc55b7157c903a55716bb73e3ae07705 \
--hash=sha256:26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6 \
--hash=sha256:2afb83308dc5c5255149ff7d3fb9964f7c9ee3d59b603ec18ccf5b0a8852e2b1 \
--hash=sha256:2db34e5c45988f36f7a08a7ab2b69638994a8923853dec2d4af121f689c66dc8 \
--hash=sha256:409c4653e0f719fa78febcb71ac417076ae5e20160aec7270c91d009837b9151 \
--hash=sha256:45a4f4cf4f4e6a55c8128f8b76b4c057027b27d4c67e3fe157fa02f27e37830d \
--hash=sha256:48eab46ef38faf1031e58dfcc9c3e71756a1108f4c9c966150b605d4a1a7f659 \
--hash=sha256:6b9e0ae298ab20d371fc26e2129fd683cfc0cfde4d157c6341722de645146537 \
--hash=sha256:6c4778afe50f413707f604828c1ad1ff81fadf6c110cb669579dea7e2e98a75e \
--hash=sha256:8c33fb99025d353c9520141f8bc989c2134a1f76bac6369cea060812f5b5c2bb \
--hash=sha256:9873a1760a274b620a135054b756f9f218fa61ca030e42df31b409f0fb738b6c \
--hash=sha256:9b069768c627f3f5623b1cbd3248c5e7e92aec62f4c98827059eed7053138cc9 \
--hash=sha256:9e4ce27a507e4886efbd3c32d120db5089b906979a4debf1d5939ec01b9dd6c5 \
--hash=sha256:acb424eaca214cb08735f1a744eceb97d014de6530c1ea23beb86d9c6f13c2ad \
--hash=sha256:c8181c7d77388fe26ab8418bb088b1a1ef5fde058c6926790c8a0a3d94075a4a \
--hash=sha256:d4afbb0840f489b60f5a580a41a1b9c3622e08ecb5eec8614d4fb4cd914c4460 \
--hash=sha256:d9ed28030797c00f4bc43c86bf819266c76a5ea61d006cd4078a93ebf7da6bfd \
--hash=sha256:e603aa7bb52e4e8ed4119a58a03b60323918467ef209e6ff9db3ac382e5cf2c6
# 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' \
cryptography==2.7 \
--hash=sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c \
--hash=sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643 \
--hash=sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216 \
--hash=sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799 \
--hash=sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a \
--hash=sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9 \
--hash=sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc \
--hash=sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8 \
--hash=sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53 \
--hash=sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1 \
--hash=sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609 \
--hash=sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292 \
--hash=sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e \
--hash=sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6 \
--hash=sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed \
--hash=sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d
distro==1.4.0 \
--hash=sha256:362dde65d846d23baee4b5c058c8586f219b5a54be1cf5fc6ff55c4578392f57 \
--hash=sha256:eedf82a470ebe7d010f1872c17237c79ab04097948800029994fa458e52fb4b4
enum34==1.1.6 \
--hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
--hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
--hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
@ -1216,18 +1219,18 @@ idna==2.8 \
ipaddress==1.0.22 \
--hash=sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794 \
--hash=sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c
josepy==1.1.0 \
--hash=sha256:1309a25aac3caeff5239729c58ff9b583f7d022ffdb1553406ddfc8e5b52b76e \
--hash=sha256:fb5c62c77d26e04df29cb5ecd01b9ce69b6fcc9e521eb1ca193b7faa2afa7086
josepy==1.2.0 \
--hash=sha256:8ea15573203f28653c00f4ac0142520777b1c59d9eddd8da3f256c6ba3cac916 \
--hash=sha256:9cec9a839fe9520f0420e4f38e7219525daccce4813296627436fe444cd002d3
mock==1.3.0 \
--hash=sha256:1e247dbecc6ce057299eb7ee019ad68314bb93152e81d9a6110d35f4d5eca0f6 \
--hash=sha256:3f573a18be94de886d1191f27c168427ef693e8dcfcecf95b170577b2eb69cbb
parsedatetime==2.4 \
--hash=sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b \
--hash=sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094
pbr==5.1.3 \
--hash=sha256:8257baf496c8522437e8a6cfe0f15e00aedc6c0e0e7c9d55eeeeab31e0853843 \
--hash=sha256:8c361cc353d988e4f5b998555c88098b9d5964c2e11acf7b0d21925a66bb5824
pbr==5.4.2 \
--hash=sha256:56e52299170b9492513c64be44736d27a512fa7e606f21942160b68ce510b4bc \
--hash=sha256:9b321c204a88d8ab5082699469f52cc94c5da45c51f114113d01b3d993c24cdf
pyOpenSSL==19.0.0 \
--hash=sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200 \
--hash=sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
@ -1236,14 +1239,14 @@ pyRFC3339==1.1 \
--hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
pycparser==2.19 \
--hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
pyparsing==2.3.1 \
--hash=sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a \
--hash=sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3
pyparsing==2.4.2 \
--hash=sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80 \
--hash=sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4
python-augeas==0.5.0 \
--hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2
pytz==2018.9 \
--hash=sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9 \
--hash=sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c
pytz==2019.2 \
--hash=sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32 \
--hash=sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7
requests==2.21.0 \
--hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
--hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b
@ -1253,15 +1256,15 @@ requests-toolbelt==0.9.1 \
six==1.12.0 \
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
urllib3==1.24.2 \
--hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
--hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3
urllib3==1.24.3 \
--hash=sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4 \
--hash=sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb
zope.component==4.5 \
--hash=sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55 \
--hash=sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4
zope.deferredimport==4.3 \
--hash=sha256:2ddef5a7ecfff132a2dd796253366ecf9748a446e30f1a0b3a636aec9d9c05c5 \
--hash=sha256:4aae9cbacb2146cca58e62be0a914f0cec034d3b2d41135ea212ca8a96f4b5ec
zope.deferredimport==4.3.1 \
--hash=sha256:57b2345e7b5eef47efcd4f634ff16c93e4265de3dcf325afc7315ade48d909e1 \
--hash=sha256:9a0c211df44aa95f1c4e6d2626f90b400f56989180d3ef96032d708da3d23e0a
zope.deprecation==4.4.0 \
--hash=sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df \
--hash=sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113
@ -1309,18 +1312,18 @@ zope.interface==4.6.0 \
--hash=sha256:d788a3999014ddf416f2dc454efa4a5dbeda657c6aba031cf363741273804c6b \
--hash=sha256:eed88ae03e1ef3a75a0e96a55a99d7937ed03e53d0cffc2451c208db445a2966 \
--hash=sha256:f99451f3a579e73b5dd58b1b08d1179791d49084371d9a47baad3b22417f0317
zope.proxy==4.3.1 \
--hash=sha256:0cbcfcafaa3b5fde7ba7a7b9a2b5f09af25c9b90087ad65f9e61359fed0ca63b \
--hash=sha256:3de631dd5054a3a20b9ebff0e375f39c0565f1fb9131200d589a6a8f379214cd \
--hash=sha256:5429134d04d42262f4dac25f6dea907f6334e9a751ffc62cb1d40226fb52bdeb \
--hash=sha256:563c2454b2d0f23bca54d2e0e4d781149b7b06cb5df67e253ca3620f37202dd2 \
--hash=sha256:5bcf773345016b1461bb07f70c635b9386e5eaaa08e37d3939dcdf12d3fdbec5 \
--hash=sha256:8d84b7aef38c693874e2f2084514522bf73fd720fde0ce2a9352a51315ffa475 \
--hash=sha256:90de9473c05819b36816b6cb957097f809691836ed3142648bf62da84b4502fe \
--hash=sha256:dd592a69fe872445542a6e1acbefb8e28cbe6b4007b8f5146da917e49b155cc3 \
--hash=sha256:e7399ab865399fce322f9cefc6f2f3e4099d087ba581888a9fea1bbe1db42a08 \
--hash=sha256:e7d1c280d86d72735a420610df592aac72332194e531a8beff43a592c3a1b8eb \
--hash=sha256:e90243fee902adb0c39eceb3c69995c0f2004bc3fdb482fbf629efc656d124ed
zope.proxy==4.3.2 \
--hash=sha256:320a7619992e42142549ebf61e14ce27683b4d14b0cbc45f7c037ba64edb560c \
--hash=sha256:824d4dbabbb7deb84f25fdb96ea1eeca436a1802c3c8d323b3eb4ac9d527d41c \
--hash=sha256:8a32eb9c94908f3544da2dae3f4a9e6961d78819b88ac6b6f4a51cee2d65f4a0 \
--hash=sha256:96265fd3bc3ea646f98482e16307a69de21402eeaaaaf4b841c1161ac2f71bb0 \
--hash=sha256:ab6d6975d9c51c13cac828ff03168de21fb562b0664c59bcdc4a4b10f39a5b17 \
--hash=sha256:af10cb772391772463f65a58348e2de5ecc06693c16d2078be276dc068bcbb54 \
--hash=sha256:b8fd3a3de3f7b6452775e92af22af5977b17b69ac86a38a3ddfe870e40a0d05f \
--hash=sha256:bb7088f1bed3b8214284a5e425dc23da56f2f28e8815b7580bfed9e245b6c0b6 \
--hash=sha256:bc29b3665eac34f14c4aef5224bef045efcfb1a7d12d78c8685858de5fbf21c0 \
--hash=sha256:c39fa6a159affeae5fe31b49d9f5b12bd674fe77271a9a324408b271440c50a7 \
--hash=sha256:e946a036ac5b9f897e986ac9dc950a34cffc857d88eae6727b8434fbc4752366
# Contains the requirements for the letsencrypt package.
#
@ -1333,18 +1336,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.37.2 \
--hash=sha256:8f6f0097fb2aac64f13e5d6974781ac85a051d84a6cb3f4d79c6b75c5ea451b8 \
--hash=sha256:e454368aa8d62559c673091b511319c130c8e0ea1c4dfa314ed7bdc91dd96ef5
acme==0.37.2 \
--hash=sha256:5666ba927a9e7bf3f9ed5a268bd5acf627b5838fb409e8401f05d2aaaee188ba \
--hash=sha256:88798fae3bc692397db79c66930bd02fcaba8a6b1fba9a62f111dda42cc47f5c
certbot-apache==0.37.2 \
--hash=sha256:e3ae7057f727506ab3796095ed66ca083f4e295d06f209ab96d2a3f37dea51b9 \
--hash=sha256:4cb44d1a7c56176a84446a11412c561479ed0fed19848632e61f104dbf6a3031
certbot-nginx==0.37.2 \
--hash=sha256:a92dffdf3daca97db5d7ae2287e505110c3fa01c035b9356abb2ef9fa32e8695 \
--hash=sha256:404f7b5b7611f0dce8773739170f306e94a59b69528cb74337e7f354936ac061
certbot==0.38.0 \
--hash=sha256:618abf3ae17c2fc3cb99baa4bf000dd5e2d7875b7811f5ef1edf6ebd7a33945f \
--hash=sha256:c27712101794e3adf54f3a3067c63be5caa507a930a79865bc654b6864121c6b
acme==0.38.0 \
--hash=sha256:6231571b4a94d6d621b28bef6f6d4846b3c2ebca840f9718d3212036c3bd2af8 \
--hash=sha256:1c1e9c0826a8f72d670b0ca28b7e6392ce4781eb33222f35133705b6551885d8
certbot-apache==0.38.0 \
--hash=sha256:0b5a2c2bcc430470b5131941ebdfde0a13e28dec38918c1a4ebea5dd35ad38bc \
--hash=sha256:2d335543e0ae9292303238736907ce6b321ac49eb49fe4e0b775abdc0ba57c62
certbot-nginx==0.38.0 \
--hash=sha256:af82944e171d2e93c81438b185f8051e742c6f47f7382cb1a647b1c7ca2b53f2 \
--hash=sha256:cecd1fa3de6e19980fdb9c3b3269b15b7da71b5748ee7ae5caddcc18dbb208ac
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -1,11 +1,11 @@
-----BEGIN PGP SIGNATURE-----
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl1dxDAACgkQTRfJlc2X
dfIoRAf/RY18bXoZNDuihCEz2zM3OIwXalOk6sPfFAGDyQ2Wh6rJhUWeV5btqItJ
uCAl707fwYZW4aYVZO8HxrZW2nNaSGk0xGQsnfMsCmiKJqj0C7MN5Ib46JTejT16
uxB329CvYsARez0CkKzu0EosZHToZFZWXyeXboCCbPzOfyhKkzBfWS+AIclvBswJ
ytPO9K7Kgu4mpKDZNvqZTSLr5atOPgIyW1+FX677ildiCLt/OUT90OVAfDGkyv86
Tv7HdIClgUsYog2xNuOqLxXoqMK/qsoPrkGr2+xpz2FvU6oX69zq1REyU+N1qPFh
XfPmX0c2m1zIeJ2wA7NH/25srEnr1w==
=6ueH
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl1uw5wACgkQTRfJlc2X
dfLRQggAium36If8RkfNxvNnKCpBteWx+wbPHhldn5gadRofFTyKXPaYpgtQ5e0P
2BIOZTwpXLBR3uAS3Rxfw4ZdoMYyuhD0Cz6SjBFHYA8ChjtCBKdeToA4e2QEV9Vi
42hBcacL7k3HhWQh+LZfu4D6pfr0ZZbZmkPWBjliEyN+g5Alfms3vzZ2aywcqoSv
iXWVwBfTk3NzVktsJVDIq2uZ1CItmYr3SyF/KRDNXTt/TL7689UF7xD7vm0RmlCZ
e6A5Si1q7RdS+OvPjyD4oKnJgJowWpFqIajOpgLVS4Z2pY3dEhe7eY7KVK5tDKhq
fTC7Elp3OKjzTXv98cEMhG6Oo67jKw==
=bbfh
-----END PGP SIGNATURE-----

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.38.0.dev0"
LE_AUTO_VERSION="0.39.0.dev0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -1336,18 +1336,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.37.2 \
--hash=sha256:8f6f0097fb2aac64f13e5d6974781ac85a051d84a6cb3f4d79c6b75c5ea451b8 \
--hash=sha256:e454368aa8d62559c673091b511319c130c8e0ea1c4dfa314ed7bdc91dd96ef5
acme==0.37.2 \
--hash=sha256:5666ba927a9e7bf3f9ed5a268bd5acf627b5838fb409e8401f05d2aaaee188ba \
--hash=sha256:88798fae3bc692397db79c66930bd02fcaba8a6b1fba9a62f111dda42cc47f5c
certbot-apache==0.37.2 \
--hash=sha256:e3ae7057f727506ab3796095ed66ca083f4e295d06f209ab96d2a3f37dea51b9 \
--hash=sha256:4cb44d1a7c56176a84446a11412c561479ed0fed19848632e61f104dbf6a3031
certbot-nginx==0.37.2 \
--hash=sha256:a92dffdf3daca97db5d7ae2287e505110c3fa01c035b9356abb2ef9fa32e8695 \
--hash=sha256:404f7b5b7611f0dce8773739170f306e94a59b69528cb74337e7f354936ac061
certbot==0.38.0 \
--hash=sha256:618abf3ae17c2fc3cb99baa4bf000dd5e2d7875b7811f5ef1edf6ebd7a33945f \
--hash=sha256:c27712101794e3adf54f3a3067c63be5caa507a930a79865bc654b6864121c6b
acme==0.38.0 \
--hash=sha256:6231571b4a94d6d621b28bef6f6d4846b3c2ebca840f9718d3212036c3bd2af8 \
--hash=sha256:1c1e9c0826a8f72d670b0ca28b7e6392ce4781eb33222f35133705b6551885d8
certbot-apache==0.38.0 \
--hash=sha256:0b5a2c2bcc430470b5131941ebdfde0a13e28dec38918c1a4ebea5dd35ad38bc \
--hash=sha256:2d335543e0ae9292303238736907ce6b321ac49eb49fe4e0b775abdc0ba57c62
certbot-nginx==0.38.0 \
--hash=sha256:af82944e171d2e93c81438b185f8051e742c6f47f7382cb1a647b1c7ca2b53f2 \
--hash=sha256:cecd1fa3de6e19980fdb9c3b3269b15b7da71b5748ee7ae5caddcc18dbb208ac
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -1,12 +1,12 @@
certbot==0.37.2 \
--hash=sha256:8f6f0097fb2aac64f13e5d6974781ac85a051d84a6cb3f4d79c6b75c5ea451b8 \
--hash=sha256:e454368aa8d62559c673091b511319c130c8e0ea1c4dfa314ed7bdc91dd96ef5
acme==0.37.2 \
--hash=sha256:5666ba927a9e7bf3f9ed5a268bd5acf627b5838fb409e8401f05d2aaaee188ba \
--hash=sha256:88798fae3bc692397db79c66930bd02fcaba8a6b1fba9a62f111dda42cc47f5c
certbot-apache==0.37.2 \
--hash=sha256:e3ae7057f727506ab3796095ed66ca083f4e295d06f209ab96d2a3f37dea51b9 \
--hash=sha256:4cb44d1a7c56176a84446a11412c561479ed0fed19848632e61f104dbf6a3031
certbot-nginx==0.37.2 \
--hash=sha256:a92dffdf3daca97db5d7ae2287e505110c3fa01c035b9356abb2ef9fa32e8695 \
--hash=sha256:404f7b5b7611f0dce8773739170f306e94a59b69528cb74337e7f354936ac061
certbot==0.38.0 \
--hash=sha256:618abf3ae17c2fc3cb99baa4bf000dd5e2d7875b7811f5ef1edf6ebd7a33945f \
--hash=sha256:c27712101794e3adf54f3a3067c63be5caa507a930a79865bc654b6864121c6b
acme==0.38.0 \
--hash=sha256:6231571b4a94d6d621b28bef6f6d4846b3c2ebca840f9718d3212036c3bd2af8 \
--hash=sha256:1c1e9c0826a8f72d670b0ca28b7e6392ce4781eb33222f35133705b6551885d8
certbot-apache==0.38.0 \
--hash=sha256:0b5a2c2bcc430470b5131941ebdfde0a13e28dec38918c1a4ebea5dd35ad38bc \
--hash=sha256:2d335543e0ae9292303238736907ce6b321ac49eb49fe4e0b775abdc0ba57c62
certbot-nginx==0.38.0 \
--hash=sha256:af82944e171d2e93c81438b185f8051e742c6f47f7382cb1a647b1c7ca2b53f2 \
--hash=sha256:cecd1fa3de6e19980fdb9c3b3269b15b7da71b5748ee7ae5caddcc18dbb208ac

View file

@ -36,6 +36,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -59,11 +59,17 @@ 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.
pywin32_req = 'pywin32>=224'
if StrictVersion(setuptools_version) >= StrictVersion('36.2'):
install_requires.append("pywin32>=224 ; sys_platform == 'win32'")
install_requires.append(pywin32_req + " ; sys_platform == 'win32'")
elif 'bdist_wheel' in sys.argv[1:]:
raise RuntimeError('Error, you are trying to build certbot wheels using an old version '
'of setuptools. Version 36.2+ of setuptools is required.')
elif os.name == 'nt':
# This branch exists to improve this package's behavior on Windows. Without
# it, if the sdist is installed on Windows with an old version of
# setuptools, pywin32 will not be specified as a dependency.
install_requires.append(pywin32_req)
dev_extras = [
'astroid==1.6.5',
@ -132,6 +138,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View file

@ -23,18 +23,8 @@ if command -v python && [ $(python -V 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | se
INITIAL_VERSION="0.20.0"
RUN_RHEL6_TESTS=1
else
# 0.33.x is the oldest version of letsencrypt-auto that works on Fedora 29+.
INITIAL_VERSION="0.33.1"
fi
# If we're on RHEL 8, the initial version of certbot-auto will fail until we do
# a release including https://github.com/certbot/certbot/pull/7240 and update
# INITIAL_VERSION above to use a version containing this fix. This works around
# the problem for now so we can successfully run tests on RHEL 8.
RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"`
RPM_DIST_VERSION=`(. /etc/os-release 2> /dev/null && echo $VERSION_ID) | cut -d '.' -f1 || echo "0"`
if [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
sudo yum install python3-virtualenv -y
# 0.37.x is the oldest version of letsencrypt-auto that works on RHEL 8.
INITIAL_VERSION="0.37.1"
fi
git checkout -f "v$INITIAL_VERSION" letsencrypt-auto

View file

@ -15,7 +15,7 @@ botocore==1.12.36
cloudflare==1.5.1
codecov==2.0.15
configparser==3.7.4
coverage==4.4.2
coverage==4.5.4
decorator==4.1.2
dns-lexicon==3.2.1
dnspython==1.15.0
@ -53,6 +53,9 @@ pyasn1==0.1.9
pyasn1-modules==0.0.10
Pygments==2.2.0
pylint==1.9.4
# If pynsist version is upgraded, our NSIS template windows-installer/template.nsi
# must be upgraded if necessary using the new built-in one from pynsist.
pynsist==2.4
pytest==3.2.5
pytest-cov==2.5.1
pytest-forked==0.2
@ -76,7 +79,7 @@ Sphinx==1.7.5
sphinx-rtd-theme==0.2.4
sphinxcontrib-websupport==1.0.1
tldextract==2.2.0
tox==2.9.1
tox==3.14.0
tqdm==4.19.4
traitlets==4.3.2
twine==1.11.0

View file

@ -228,7 +228,7 @@ commands =
--acme-server={env:ACME_SERVER:pebble} \
--cov=acme --cov=certbot --cov=certbot_nginx --cov=certbot_apache \
--cov-report= --cov-config=certbot-ci/certbot_integration_tests/.coveragerc
coverage report --include 'certbot/*' --show-missing --fail-under=66
coverage report --include 'certbot/*' --show-missing --fail-under=65
coverage report --include 'certbot-nginx/*' --show-missing --fail-under=74
coverage report --include 'certbot-apache/*' --show-missing --fail-under=55
passenv = DOCKER_*

2
windows-installer/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
build
build.*

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

View file

@ -0,0 +1,143 @@
#!/usr/bin/env python3
import ctypes
import struct
import subprocess
import os
import sys
import shutil
import time
PYTHON_VERSION = (3, 7, 4)
PYTHON_BITNESS = 32
def main():
build_path, repo_path, venv_path, venv_python = _prepare_environment()
_copy_assets(build_path, repo_path)
installer_cfg_path = _generate_pynsist_config(repo_path, build_path)
_prepare_build_tools(venv_path, venv_python, repo_path)
_compile_wheels(repo_path, build_path, venv_python)
_build_installer(installer_cfg_path, venv_path)
print('Done')
def _build_installer(installer_cfg_path, venv_path):
print('Build the installer')
subprocess.check_call([os.path.join(venv_path, 'Scripts', 'pynsist.exe'), installer_cfg_path])
def _compile_wheels(repo_path, build_path, venv_python):
print('Compile wheels')
wheels_path = os.path.join(build_path, 'wheels')
os.makedirs(wheels_path)
certbot_packages = ['acme', '.']
# Uncomment following line to include all DNS plugins in the installer
# certbot_packages.extend([name for name in os.listdir(repo_path) if name.startswith('certbot-dns-')])
wheels_project = [os.path.join(repo_path, package) for package in certbot_packages]
command = [venv_python, '-m', 'pip', 'wheel', '-w', wheels_path]
command.extend(wheels_project)
subprocess.check_call(command)
def _prepare_build_tools(venv_path, venv_python, repo_path):
print('Prepare build tools')
subprocess.check_call([sys.executable, '-m', 'venv', venv_path])
subprocess.check_call(['choco', 'upgrade', '-y', 'nsis'])
subprocess.check_call([venv_python, '-m', 'pip', 'install', '--upgrade', 'pip'])
subprocess.check_call([venv_python, os.path.join(repo_path, 'tools', 'pip_install.py'), 'wheel', 'pynsist'])
def _copy_assets(build_path, repo_path):
print('Copy assets')
if os.path.exists(build_path):
os.rename(build_path, '{0}.{1}.bak'.format(build_path, int(time.time())))
os.makedirs(build_path)
shutil.copy(os.path.join(repo_path, 'windows-installer', 'certbot.ico'), build_path)
shutil.copy(os.path.join(repo_path, 'windows-installer', 'run.bat'), build_path)
shutil.copy(os.path.join(repo_path, 'windows-installer', 'template.nsi'), build_path)
shutil.copy(os.path.join(repo_path, 'windows-installer', 'renew-up.ps1'), build_path)
shutil.copy(os.path.join(repo_path, 'windows-installer', 'renew-down.ps1'), build_path)
def _generate_pynsist_config(repo_path, build_path):
print('Generate pynsist configuration')
installer_cfg_path = os.path.join(build_path, 'installer.cfg')
certbot_version = subprocess.check_output([sys.executable, '-c', 'import certbot; print(certbot.__version__)'],
universal_newlines=True, cwd=repo_path).strip()
with open(os.path.join(installer_cfg_path), 'w') as file_h:
file_h.write("""\
[Application]
name=Certbot
version={certbot_version}
icon=certbot.ico
publisher=Electronic Frontier Foundation
target=$INSTDIR\\run.bat
[Build]
directory=nsis
nsi_template=template.nsi
installer_name=certbot-{certbot_version}-installer-{installer_suffix}.exe
[Python]
version={python_version}
bitness={python_bitness}
[Include]
local_wheels=wheels\\*.whl
files=run.bat
renew-up.ps1
renew-down.ps1
[Command certbot]
entry_point=certbot.main:main
""".format(certbot_version=certbot_version,
installer_suffix='win_amd64' if PYTHON_BITNESS == 64 else 'win32',
python_bitness=PYTHON_BITNESS,
python_version='.'.join([str(item) for item in PYTHON_VERSION])))
return installer_cfg_path
def _prepare_environment():
print('Prepare environment')
try:
subprocess.check_output(['choco', '--version'])
except subprocess.CalledProcessError:
raise RuntimeError('Error: Chocolatey (https://chocolatey.org/) needs '
'to be installed to run this script.')
script_path = os.path.realpath(__file__)
repo_path = os.path.dirname(os.path.dirname(script_path))
build_path = os.path.join(repo_path, 'windows-installer', 'build')
venv_path = os.path.join(build_path, 'venv-config')
venv_python = os.path.join(venv_path, 'Scripts', 'python.exe')
return build_path, repo_path, venv_path, venv_python
if __name__ == '__main__':
if not os.name == 'nt':
raise RuntimeError('This script must be run under Windows.')
if ctypes.windll.shell32.IsUserAnAdmin() == 0:
# Administrator privileges are required to properly install NSIS through Chocolatey
raise RuntimeError('This script must be run with administrator privileges.')
if sys.version_info[:2] != PYTHON_VERSION[:2]:
raise RuntimeError('This script must be run with Python {0}'
.format('.'.join([str(item) for item in PYTHON_VERSION[0:2]])))
if struct.calcsize('P') * 8 != PYTHON_BITNESS:
raise RuntimeError('This script must be run with a {0} bit version of Python.'
.format(PYTHON_BITNESS))
main()

View file

@ -0,0 +1,6 @@
$taskName = "Certbot Renew Task"
$exists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName}
if ($exists) {
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
}

View file

@ -0,0 +1,15 @@
function Get-ScriptDirectory { Split-Path $MyInvocation.ScriptName }
$down = Join-Path (Get-ScriptDirectory) 'renew-down.ps1'
& $down
$taskName = "Certbot Renew Task"
$action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -Command "certbot renew"'
$delay = New-TimeSpan -Hours 12
$triggerAM = New-ScheduledTaskTrigger -Daily -At 12am -RandomDelay $delay
$triggerPM = New-ScheduledTaskTrigger -Daily -At 12pm -RandomDelay $delay
# NB: For now scheduled task is set up under SYSTEM account because Certbot Installer installs Certbot for all users.
# If in the future we allow the Installer to install Certbot for one specific user, the scheduled task will need to
# switch to this user, since Certbot will be available only for him.
$principal = New-ScheduledTaskPrincipal -UserId SYSTEM -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -Action $action -Trigger $triggerAM,$triggerPM -TaskName $taskName -Description "Execute twice a day the 'certbot renew' command, to renew managed certificates if needed." -Principal $principal

31
windows-installer/run.bat Normal file
View file

@ -0,0 +1,31 @@
@echo off
:: BatchGotAdmin
:-------------------------------------
REM --> Check for permissions
IF "%PROCESSOR_ARCHITECTURE%" EQU "amd64" (
>nul 2>&1 "%SYSTEMROOT%\SysWOW64\cacls.exe" "%SYSTEMROOT%\SysWOW64\config\system"
) ELSE (
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
)
REM --> If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
echo Requesting administrative privileges...
goto UACPrompt
) else ( goto gotAdmin )
:UACPrompt
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
set params= %*
echo UAC.ShellExecute "cmd.exe", "/c ""%~s0"" %params:"=""%", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
del "%temp%\getadmin.vbs"
exit /B
:gotAdmin
pushd "%CD%"
CD /D "%~dp0"
:--------------------------------------
cmd.exe /k echo You can run 'certbot' commands here. Type 'certbot --help' for more information.

View file

@ -0,0 +1,257 @@
; This NSIS template is based on the built-in one in pynsist 2.3.
; Added lines are enclosed within "CERTBOT CUSTOM BEGIN/END" comments.
; If pynsist is upgraded, this template must be updated if necessary using the new built-in one.
; Original file can be found here: https://github.com/takluyver/pynsist/blob/2.4/nsist/pyapp.nsi
!define PRODUCT_NAME "[[ib.appname]]"
!define PRODUCT_VERSION "[[ib.version]]"
!define PY_VERSION "[[ib.py_version]]"
!define PY_MAJOR_VERSION "[[ib.py_major_version]]"
!define BITNESS "[[ib.py_bitness]]"
!define ARCH_TAG "[[arch_tag]]"
!define INSTALLER_NAME "[[ib.installer_name]]"
!define PRODUCT_ICON "[[icon]]"
; Marker file to tell the uninstaller that it's a user installation
!define USER_INSTALL_MARKER _user_install_marker
SetCompressor lzma
; CERTBOT CUSTOM BEGIN
; Administrator privileges are required to insert a new task in Windows Scheduler.
; Also comment out some options to disable ability to choose AllUsers/CurrentUser install mode.
; As a result, installer run always with admin privileges (because of MULTIUSER_EXECUTIONLEVEL),
; using the AllUsers installation mode by default (because of MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER
; not set), and this default behavior cannot be overridden (because of MULTIUSER_MUI not set).
; See https://nsis.sourceforge.io/Docs/MultiUser/Readme.html
!define MULTIUSER_EXECUTIONLEVEL Admin
;!define MULTIUSER_EXECUTIONLEVEL Highest
;!define MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER
;!define MULTIUSER_MUI
;!define MULTIUSER_INSTALLMODE_COMMANDLINE
; CERTBOT CUSTOM END
!define MULTIUSER_INSTALLMODE_INSTDIR "[[ib.appname]]"
[% if ib.py_bitness == 64 %]
!define MULTIUSER_INSTALLMODE_FUNCTION correct_prog_files
[% endif %]
!include MultiUser.nsh
[% block modernui %]
; Modern UI installer stuff
!include "MUI2.nsh"
!define MUI_ABORTWARNING
!define MUI_ICON "[[icon]]"
!define MUI_UNICON "[[icon]]"
; UI pages
[% block ui_pages %]
!insertmacro MUI_PAGE_WELCOME
[% if license_file %]
!insertmacro MUI_PAGE_LICENSE [[license_file]]
[% endif %]
; CERTBOT CUSTOM BEGIN
; Disable the installation mode page (AllUsers/CurrentUser)
;!insertmacro MULTIUSER_PAGE_INSTALLMODE
; CERTBOT CUSTOM END
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
[% endblock ui_pages %]
!insertmacro MUI_LANGUAGE "English"
[% endblock modernui %]
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "${INSTALLER_NAME}"
ShowInstDetails show
Section -SETTINGS
SetOutPath "$INSTDIR"
SetOverwrite ifnewer
SectionEnd
[% block sections %]
Section "!${PRODUCT_NAME}" sec_app
SetRegView [[ib.py_bitness]]
SectionIn RO
File ${PRODUCT_ICON}
SetOutPath "$INSTDIR\pkgs"
File /r "pkgs\*.*"
SetOutPath "$INSTDIR"
; Marker file for per-user install
StrCmp $MultiUser.InstallMode CurrentUser 0 +3
FileOpen $0 "$INSTDIR\${USER_INSTALL_MARKER}" w
FileClose $0
SetFileAttributes "$INSTDIR\${USER_INSTALL_MARKER}" HIDDEN
[% block install_files %]
; Install files
[% for destination, group in grouped_files %]
SetOutPath "[[destination]]"
[% for file in group %]
File "[[ file ]]"
[% endfor %]
[% endfor %]
; Install directories
[% for dir, destination in ib.install_dirs %]
SetOutPath "[[ pjoin(destination, dir) ]]"
File /r "[[dir]]\*.*"
[% endfor %]
[% endblock install_files %]
[% block install_shortcuts %]
; Install shortcuts
; The output path becomes the working directory for shortcuts
SetOutPath "%HOMEDRIVE%\%HOMEPATH%"
[% if single_shortcut %]
[% for scname, sc in ib.shortcuts.items() %]
CreateShortCut "$SMPROGRAMS\[[scname]].lnk" "[[sc['target'] ]]" \
'[[ sc['parameters'] ]]' "$INSTDIR\[[ sc['icon'] ]]"
[% endfor %]
[% else %]
[# Multiple shortcuts: create a directory for them #]
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
[% for scname, sc in ib.shortcuts.items() %]
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\[[scname]].lnk" "[[sc['target'] ]]" \
'[[ sc['parameters'] ]]' "$INSTDIR\[[ sc['icon'] ]]"
[% endfor %]
[% endif %]
SetOutPath "$INSTDIR"
[% endblock install_shortcuts %]
[% block install_commands %]
[% if has_commands %]
DetailPrint "Setting up command-line launchers..."
nsExec::ExecToLog '[[ python ]] -Es "$INSTDIR\_assemble_launchers.py" [[ python ]] "$INSTDIR\bin"'
StrCmp $MultiUser.InstallMode CurrentUser 0 AddSysPathSystem
; Add to PATH for current user
nsExec::ExecToLog '[[ python ]] -Es "$INSTDIR\_system_path.py" add_user "$INSTDIR\bin"'
GoTo AddedSysPath
AddSysPathSystem:
; Add to PATH for all users
nsExec::ExecToLog '[[ python ]] -Es "$INSTDIR\_system_path.py" add "$INSTDIR\bin"'
AddedSysPath:
[% endif %]
[% endblock install_commands %]
; Byte-compile Python files.
DetailPrint "Byte-compiling Python modules..."
nsExec::ExecToLog '[[ python ]] -m compileall -q "$INSTDIR\pkgs"'
WriteUninstaller $INSTDIR\uninstall.exe
; Add ourselves to Add/remove programs
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayName" "${PRODUCT_NAME}"
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"InstallLocation" "$INSTDIR"
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayIcon" "$INSTDIR\${PRODUCT_ICON}"
[% if ib.publisher is not none %]
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"Publisher" "[[ib.publisher]]"
[% endif %]
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayVersion" "${PRODUCT_VERSION}"
WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"NoModify" 1
WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"NoRepair" 1
; CERTBOT CUSTOM BEGIN
; Execute ps script to create the certbot renew task
DetailPrint "Setting up certbot renew scheduled task"
nsExec::ExecToStack 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "$INSTDIR\renew-up.ps1"'
; CERTBOT CUSTOM END
; Check if we need to reboot
IfRebootFlag 0 noreboot
MessageBox MB_YESNO "A reboot is required to finish the installation. Do you wish to reboot now?" \
/SD IDNO IDNO noreboot
Reboot
noreboot:
SectionEnd
Section "Uninstall"
; CERTBOT CUSTOM BEGIN
; Execute ps script to remove the certbot renew task
nsExec::ExecToStack 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "$INSTDIR\renew-down.ps1"'
; CERTBOT CUSTOM END
SetRegView [[ib.py_bitness]]
SetShellVarContext all
IfFileExists "$INSTDIR\${USER_INSTALL_MARKER}" 0 +3
SetShellVarContext current
Delete "$INSTDIR\${USER_INSTALL_MARKER}"
Delete $INSTDIR\uninstall.exe
Delete "$INSTDIR\${PRODUCT_ICON}"
RMDir /r "$INSTDIR\pkgs"
; Remove ourselves from %PATH%
[% block uninstall_commands %]
[% if has_commands %]
nsExec::ExecToLog '[[ python ]] -Es "$INSTDIR\_system_path.py" remove "$INSTDIR\bin"'
[% endif %]
[% endblock uninstall_commands %]
[% block uninstall_files %]
; Uninstall files
[% for file, destination in ib.install_files %]
Delete "[[pjoin(destination, file)]]"
[% endfor %]
; Uninstall directories
[% for dir, destination in ib.install_dirs %]
RMDir /r "[[pjoin(destination, dir)]]"
[% endfor %]
[% endblock uninstall_files %]
[% block uninstall_shortcuts %]
; Uninstall shortcuts
[% if single_shortcut %]
[% for scname in ib.shortcuts %]
Delete "$SMPROGRAMS\[[scname]].lnk"
[% endfor %]
[% else %]
RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
[% endif %]
[% endblock uninstall_shortcuts %]
RMDir $INSTDIR
DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
SectionEnd
[% endblock sections %]
; Functions
Function .onMouseOverSection
; Find which section the mouse is over, and set the corresponding description.
FindWindow $R0 "#32770" "" $HWNDPARENT
GetDlgItem $R0 $R0 1043 ; description item (must be added to the UI)
[% block mouseover_messages %]
StrCmp $0 ${sec_app} "" +2
SendMessage $R0 ${WM_SETTEXT} 0 "STR:${PRODUCT_NAME}"
[% endblock mouseover_messages %]
FunctionEnd
Function .onInit
!insertmacro MULTIUSER_INIT
FunctionEnd
Function un.onInit
!insertmacro MULTIUSER_UNINIT
FunctionEnd
[% if ib.py_bitness == 64 %]
Function correct_prog_files
; The multiuser machinery doesn't know about the different Program files
; folder for 64-bit applications. Override the install dir it set.
StrCmp $MultiUser.InstallMode AllUsers 0 +2
StrCpy $INSTDIR "$PROGRAMFILES64\${MULTIUSER_INSTALLMODE_INSTDIR}"
FunctionEnd
[% endif %]