mirror of
https://github.com/certbot/certbot.git
synced 2026-06-04 06:15:36 -04:00
Committing before git pull to make merge error go away
This commit is contained in:
commit
defdf39701
87 changed files with 1601 additions and 1020 deletions
|
|
@ -169,7 +169,7 @@ notifications:
|
|||
email: false
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#letsencrypt"
|
||||
- "chat.freenode.net#letsencrypt-dev"
|
||||
on_success: never
|
||||
on_failure: always
|
||||
use_notice: true
|
||||
|
|
|
|||
39
CHANGELOG.md
39
CHANGELOG.md
|
|
@ -2,6 +2,45 @@
|
|||
|
||||
Certbot adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 0.17.0 - 2017-08-02
|
||||
|
||||
### Added
|
||||
|
||||
* Support in our nginx plugin for modifying SSL server blocks that do
|
||||
not contain certificate or key directives.
|
||||
* A `--max-log-backups` flag to allow users to configure or even completely
|
||||
disable Certbot's built in log rotation.
|
||||
* A `--user-agent-comment` flag to allow people who build tools around Certbot
|
||||
to differentiate their user agent string by adding a comment to its default
|
||||
value.
|
||||
|
||||
### Changed
|
||||
|
||||
* Due to some awesome work by
|
||||
[cryptography project](https://github.com/pyca/cryptography), compilation can
|
||||
now be avoided on most systems when using certbot-auto. This eliminates many
|
||||
problems people have had in the past such as running out of memory, having
|
||||
invalid headers/libraries, and changes to the OS packages on their system
|
||||
after compilation breaking Certbot.
|
||||
* The `--renew-hook` flag has been hidden in favor of `--deploy-hook`. This new
|
||||
flag works exactly the same way except it is always run when a certificate is
|
||||
issued rather than just when it is renewed.
|
||||
* We have started printing deprecation warnings in certbot-auto for
|
||||
experimentally supported systems with OS packages available.
|
||||
* A certificate lineage's name is included in error messages during renewal.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Encoding errors that could occur when parsing error messages from the ACME
|
||||
server containing Unicode have been resolved.
|
||||
* certbot-auto no longer prints misleading messages about there being a newer
|
||||
pip version available when installation fails.
|
||||
* Certbot's ACME library now properly extracts domains from critical SAN
|
||||
extensions.
|
||||
|
||||
More details about these changes can be found on our GitHub repo:
|
||||
https://github.com/certbot/certbot/issues?q=is%3Aissue+milestone%3A0.17.0+is%3Aclosed
|
||||
|
||||
## 0.16.0 - 2017-07-05
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
136
certbot-auto
136
certbot-auto
|
|
@ -28,7 +28,7 @@ if [ -z "$VENV_PATH" ]; then
|
|||
VENV_PATH="$XDG_DATA_HOME/$VENV_NAME"
|
||||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
LE_AUTO_VERSION="0.16.0"
|
||||
LE_AUTO_VERSION="0.17.0"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
|
|
@ -200,6 +200,25 @@ ExperimentalBootstrap() {
|
|||
fi
|
||||
}
|
||||
|
||||
DeprecationBootstrap() {
|
||||
# Arguments: Platform name, bootstrap function name
|
||||
if [ "$DEBUG" = 1 ]; then
|
||||
if [ "$2" != "" ]; then
|
||||
BootstrapMessage $1
|
||||
$2
|
||||
fi
|
||||
else
|
||||
error "WARNING: certbot-auto support for this $1 is DEPRECATED!"
|
||||
error "Please visit certbot.eff.org to learn how to download a version of"
|
||||
error "Certbot that is packaged for your system. While an existing version"
|
||||
error "of certbot-auto may work currently, we have stopped supporting updating"
|
||||
error "system packages for your system. Please switch to a packaged version"
|
||||
error "as soon as possible."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
DeterminePythonVersion() {
|
||||
for LE_PYTHON in "$LE_PYTHON" python2.7 python27 python2 python; do
|
||||
# Break (while keeping the LE_PYTHON value) if found.
|
||||
|
|
@ -630,11 +649,11 @@ Bootstrap() {
|
|||
elif [ -f /etc/manjaro-release ]; then
|
||||
ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon
|
||||
elif [ -f /etc/gentoo-release ]; then
|
||||
ExperimentalBootstrap "Gentoo" BootstrapGentooCommon
|
||||
DeprecationBootstrap "Gentoo" BootstrapGentooCommon
|
||||
elif uname | grep -iq FreeBSD ; then
|
||||
ExperimentalBootstrap "FreeBSD" BootstrapFreeBsd
|
||||
DeprecationBootstrap "FreeBSD" BootstrapFreeBsd
|
||||
elif uname | grep -iq Darwin ; then
|
||||
ExperimentalBootstrap "macOS" BootstrapMac
|
||||
DeprecationBootstrap "macOS" BootstrapMac
|
||||
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
|
||||
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
|
||||
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
|
||||
|
|
@ -751,25 +770,37 @@ ConfigArgParse==0.10.0 \
|
|||
--hash=sha256:3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7
|
||||
configobj==5.0.6 \
|
||||
--hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
|
||||
cryptography==1.9 \
|
||||
--hash=sha256:469a9d3d851038f1eb7d7f77bb08bb4775b41483372be450e25b293fe57bd59e \
|
||||
--hash=sha256:533143321d15c8743f91eec5c5f495c1b5cad9a25de8f6dab01eddd6b416903e \
|
||||
--hash=sha256:2230c186182d773064d06242e0fa604cd718bfff28aa9c5ae73d7e426e98a151 \
|
||||
--hash=sha256:3dc94ed5a26b8553a325767358f505c0a43e0c89df078647f77a4d022ddcdc57 \
|
||||
--hash=sha256:2eb8297b877cb6b56216750fa7017c9f5786bec8afd6a0f1aaace02cbfb6195f \
|
||||
--hash=sha256:025a96e48164106f2082b00f42bf430cf21f09e203e42585a712e420b75cbff0 \
|
||||
--hash=sha256:61eb3534f8ed2415dd708b28919205d523f220e4cd5b8165844edfdd4a649b8e \
|
||||
--hash=sha256:5474fe5ce6b517d3086e0231b6ad88f8978c551c4379f91c3d619c308490f0d7 \
|
||||
--hash=sha256:5ff169869624e23767d70db274f13a9ea4e97c029425a1224aa5e049e84ce2af \
|
||||
--hash=sha256:c26e057a2de13e97e708328d295c5ac4cd3eab4a5c42ce727dd1a53316034b8a \
|
||||
--hash=sha256:7db719432648f14ea33edffc5f75330c595804eac86ca916528b35ce50a8bfd6 \
|
||||
--hash=sha256:ca72537a7064bb80e34b6908e576ffc8e2c2cad29a7168f48d0999df089695c3 \
|
||||
--hash=sha256:2a5e577f5d2093e51486b4ec02b51bb5adb165b98fee99929d5af0813e90b469 \
|
||||
--hash=sha256:9d9da8bac2e31003d092f5ef6981a725c77c4e9a30638436884d61ad39f9a1ee \
|
||||
--hash=sha256:fab8ec6866e384d9827d5dc02a1383e991a6c05c54f818316c4b829e56ca2ba3 \
|
||||
--hash=sha256:365eb804362e581c9a02e7a610b30514f07dd77b2a38aed338eb5192446bbc58 \
|
||||
--hash=sha256:2908f709f02711dbb10561a9f154d2f7d1792385e2341e9708539cc4ecfb8667 \
|
||||
--hash=sha256:5518337022718029e367d982642f3e3523541e098ad671672a90b82474c84882
|
||||
cryptography==2.0.2 \
|
||||
--hash=sha256:187ae17358436d2c760f28c2aeb02fefa3f37647a9c5b6f7f7c3e83cd1c5a972 \
|
||||
--hash=sha256:19e43a13bbf52028dd1e810c803f2ad8880d0692d772f98d42e1eaf34bdee3d6 \
|
||||
--hash=sha256:da9291502cbc87dc0284a20c56876e4d2e68deac61cc43df4aec934e44ca97b1 \
|
||||
--hash=sha256:0954f8813095f581669330e0a2d5e726c33ac7f450c1458fac58bab54595e516 \
|
||||
--hash=sha256:d68b0cc40a8432ed3fc84876c519de704d6001800ec22b136e75ae841910c45b \
|
||||
--hash=sha256:2f8ad9580ab4da645cfea52a91d2da99a49a1e76616d8be68441a986fad652b0 \
|
||||
--hash=sha256:cc00b4511294f5f6b65c4e77a1a9c62f52490a63d2c120f3872176b40a82351e \
|
||||
--hash=sha256:cf896020f6a9f095a547b3d672c8db1ef2ed71fca11250731fa1d4a4cb8b1590 \
|
||||
--hash=sha256:e0fdb8322206fa02aa38f71519ff75dce2eb481b7e1110e2936795cb376bb6ee \
|
||||
--hash=sha256:277538466657ca5d6637f80be100242f9831d75138b788d718edd3aab34621f8 \
|
||||
--hash=sha256:2c77eb0560f54ce654ab82d6b2a64327a71ee969b29022bf9746ca311c9f5069 \
|
||||
--hash=sha256:755a7853b679e79d0a799351c092a9b0271f95ff54c8dd8823d8b527a2926a86 \
|
||||
--hash=sha256:77197a2d525e761cdd4c771180b4bd0d80703654c6385e4311cbbbe2beb56fa1 \
|
||||
--hash=sha256:eb8bb79d0ab00c931c8333b745f06fec481a51c52d70acd4ee95d6093ba5c386 \
|
||||
--hash=sha256:131f61de82ef28f3e20beb4bfc24f9692d28cecfd704e20e6c7f070f7793013a \
|
||||
--hash=sha256:ac35435974b2e27cd4520f29c191d7da36f4189aa3264e52c4c6c6d089ab6142 \
|
||||
--hash=sha256:04b6ea99daa2a8460728794213d76d45ad58ea247dc7e7ff148d7dd726e87863 \
|
||||
--hash=sha256:2b9442f8b4c3d575f6cc3db0e856034e0f5a9d55ecd636f52d8c496795b26952 \
|
||||
--hash=sha256:b3d3b3ecba1fe1bdb6f180770a137f877c8f07571f7b2934bb269475bcf0e5e8 \
|
||||
--hash=sha256:670a58c0d75cb0e78e73dd003bd96d4440bbb1f2bc041dcf7b81767ca4fb0ce9 \
|
||||
--hash=sha256:5af84d23bdb86b5e90aca263df1424b43f1748480bfcde3ac2a3cbe622612468 \
|
||||
--hash=sha256:ba22e8eefabdd7aca37d0c0c00d2274000d2cebb5cce9e5a710cb55bf8797b31 \
|
||||
--hash=sha256:b798b22fa7e92b439547323b8b719d217f1e1b7677585cfeeedf3b55c70bb7fb \
|
||||
--hash=sha256:59cff28af8cce96cb7e94a459726e1d88f6f5fa75097f9dcbebd99118d64ea4c \
|
||||
--hash=sha256:fe859e445abc9ba9e97950ddafb904e23234c4ecb76b0fae6c86e80592ce464a \
|
||||
--hash=sha256:655f3c474067f1e277430f23cc0549f0b1dc99b82aec6e53f80b9b2db7f76f11 \
|
||||
--hash=sha256:0ebc2be053c9a03a2f3e20a466e87bf12a51586b3c79bd2a22171b073a805346 \
|
||||
--hash=sha256:01e6e60654df64cca53733cda39446d67100c819c181d403afb120e0d2a71e1b \
|
||||
--hash=sha256:d46f4e5d455cb5563685c52ef212696f0a6cc1ea627603218eabbd8a095291d8 \
|
||||
--hash=sha256:3780b2663ee7ebb37cb83263326e3cd7f8b2ea439c448539d4b87de12c8d06ab
|
||||
enum34==1.1.2 \
|
||||
--hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \
|
||||
--hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501
|
||||
|
|
@ -876,18 +907,18 @@ letsencrypt==0.7.0 \
|
|||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==0.16.0 \
|
||||
--hash=sha256:e1cc2479f4f149a7128b67192c3f5f6c111b6b9ddcac421ebee8ac5030d5b09b \
|
||||
--hash=sha256:795801fd6b06b32060e364ac045312e6b26c6272d5ca32878277e5a2afdee186
|
||||
acme==0.16.0 \
|
||||
--hash=sha256:31592a744f7a6e7cbb4c5daf2deebc9af6b03997d6f80e5becc203ab8694edcf \
|
||||
--hash=sha256:538b69134cc50bdcdcc081b844c85158509022c61d7abc1f44216beeb95de9cd
|
||||
certbot-apache==0.16.0 \
|
||||
--hash=sha256:337f84f391c7d7c31d84376e7a8c882ac119112a4aabceadd1a7de6a2f01ca06 \
|
||||
--hash=sha256:f1f37b56e1ceb0a28ccf51d54ca34444e6a708448845ef25372e223b9a82c4d4
|
||||
certbot-nginx==0.16.0 \
|
||||
--hash=sha256:1d57428202f8e7abdd99c3ddbcf374aad5f69c4262fe8dae53d2016e4ae04ded \
|
||||
--hash=sha256:77711655514d707ddf728195f00b2f6cdd1ad9db52440276b4a67664479c6954
|
||||
certbot==0.17.0 \
|
||||
--hash=sha256:64c25c7123357feffded6408660bc6f5c7d493dd635ae172081d21473075a86a \
|
||||
--hash=sha256:43f5b26c3f314d14babf79a3bdf3522e4fc9eef867a0681c426f113c650a669c
|
||||
acme==0.17.0 \
|
||||
--hash=sha256:501710171633af13fc52aa61d0277a6fe335f7477db5810e72239aaf4f3a09e7 \
|
||||
--hash=sha256:3ccbe4aaeb98c77b98ee4093b4e4adb76a1a24cbdfec0130c489c206f1d9b66e
|
||||
certbot-apache==0.17.0 \
|
||||
--hash=sha256:17a7e8d7526d838610e68b96cf052af17c4055655b76b06d1cbc74857d90a216 \
|
||||
--hash=sha256:29b9e7bc5eaaff6dc4bce8398e35eeacdf346126aad68cac3d41bb87df20a6b9
|
||||
certbot-nginx==0.17.0 \
|
||||
--hash=sha256:980c9a33a79ab839a089a0085ff0c5414f01f47b6db26ed342df25916658cec9 \
|
||||
--hash=sha256:e573f8b4283172755c07b9cca8a8da7ef2d31b4df763881394b5339b2d42994a
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
|
@ -915,6 +946,7 @@ anything goes wrong, it will exit with a non-zero status code.
|
|||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
from __future__ import print_function
|
||||
from distutils.version import StrictVersion
|
||||
from hashlib import sha256
|
||||
from os.path import join
|
||||
from pipes import quote
|
||||
|
|
@ -949,12 +981,14 @@ except ImportError:
|
|||
from urllib.parse import urlparse # 3.4
|
||||
|
||||
|
||||
__version__ = 1, 1, 1
|
||||
__version__ = 1, 3, 0
|
||||
PIP_VERSION = '9.0.1'
|
||||
|
||||
|
||||
# wheel has a conditional dependency on argparse:
|
||||
maybe_argparse = (
|
||||
[('https://pypi.python.org/packages/source/a/argparse/'
|
||||
[('https://pypi.python.org/packages/18/dd/'
|
||||
'e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/'
|
||||
'argparse-1.4.0.tar.gz',
|
||||
'62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')]
|
||||
if version_info < (2, 7, 0) else [])
|
||||
|
|
@ -962,13 +996,19 @@ maybe_argparse = (
|
|||
|
||||
PACKAGES = maybe_argparse + [
|
||||
# Pip has no dependencies, as it vendors everything:
|
||||
('https://pypi.python.org/packages/source/p/pip/pip-8.0.3.tar.gz',
|
||||
'30f98b66f3fe1069c529a491597d34a1c224a68640c82caf2ade5f88aa1405e8'),
|
||||
('https://pypi.python.org/packages/11/b6/'
|
||||
'abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/'
|
||||
'pip-{0}.tar.gz'
|
||||
.format(PIP_VERSION),
|
||||
'09f243e1a7b461f654c26a725fa373211bb7ff17a9300058b205c61658ca940d'),
|
||||
# This version of setuptools has only optional dependencies:
|
||||
('https://pypi.python.org/packages/source/s/setuptools/'
|
||||
('https://pypi.python.org/packages/69/65/'
|
||||
'4c544cde88d4d876cdf5cbc5f3f15d02646477756d89547e9a7ecd6afa76/'
|
||||
'setuptools-20.2.2.tar.gz',
|
||||
'24fcfc15364a9fe09a220f37d2dcedc849795e3de3e4b393ee988e66a9cbd85a'),
|
||||
('https://pypi.python.org/packages/source/w/wheel/wheel-0.29.0.tar.gz',
|
||||
('https://pypi.python.org/packages/c9/1d/'
|
||||
'bd19e691fd4cfe908c76c429fe6e4436c9e83583c4414b54f6c85471954a/'
|
||||
'wheel-0.29.0.tar.gz',
|
||||
'1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648')
|
||||
]
|
||||
|
||||
|
|
@ -1018,11 +1058,21 @@ def hashed_download(url, temp, digest):
|
|||
|
||||
|
||||
def main():
|
||||
pip_version = StrictVersion(check_output(['pip', '--version'])
|
||||
.decode('utf-8').split()[1])
|
||||
min_pip_version = StrictVersion(PIP_VERSION)
|
||||
if pip_version >= min_pip_version:
|
||||
return 0
|
||||
has_pip_cache = pip_version >= StrictVersion('6.0')
|
||||
|
||||
temp = mkdtemp(prefix='pipstrap-')
|
||||
try:
|
||||
downloads = [hashed_download(url, temp, digest)
|
||||
for url, digest in PACKAGES]
|
||||
check_output('pip install --no-index --no-deps -U ' +
|
||||
# Disable cache since we're not using it and it otherwise
|
||||
# sometimes throws permission warnings:
|
||||
('--no-cache-dir ' if has_pip_cache else '') +
|
||||
' '.join(quote(d) for d in downloads),
|
||||
shell=True)
|
||||
except HashError as exc:
|
||||
|
|
@ -1045,9 +1095,9 @@ UNLIKELY_EOF
|
|||
PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py"
|
||||
set +e
|
||||
if [ "$VERBOSE" = 1 ]; then
|
||||
"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt"
|
||||
"$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt"
|
||||
else
|
||||
PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1`
|
||||
PIP_OUT=`"$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1`
|
||||
fi
|
||||
PIP_STATUS=$?
|
||||
set -e
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ MAINTAINER Brad Warren <bmw@eff.org>
|
|||
|
||||
# TODO: Install non-default Python versions for tox.
|
||||
# TODO: Install Apache/Nginx for plugin development.
|
||||
COPY certbot-auto /opt/certbot/src/certbot-auto
|
||||
RUN /opt/certbot/src/certbot-auto -n --os-packages-only
|
||||
COPY letsencrypt-auto-source /opt/certbot/src/letsencrypt-auto-source
|
||||
RUN /opt/certbot/src/letsencrypt-auto-source/letsencrypt-auto --os-packages-only
|
||||
|
||||
# the above is not likely to change, so by putting it further up the
|
||||
# Dockerfile we make sure we cache as much as possible
|
||||
|
|
@ -29,16 +29,18 @@ COPY acme /opt/certbot/src/acme/
|
|||
COPY certbot-apache /opt/certbot/src/certbot-apache/
|
||||
COPY certbot-nginx /opt/certbot/src/certbot-nginx/
|
||||
COPY certbot-compatibility-test /opt/certbot/src/certbot-compatibility-test/
|
||||
COPY tools /opt/certbot/src/tools
|
||||
|
||||
RUN virtualenv --no-site-packages -p python2 /opt/certbot/venv && \
|
||||
/opt/certbot/venv/bin/pip install -U setuptools && \
|
||||
/opt/certbot/venv/bin/pip install -U pip && \
|
||||
/opt/certbot/venv/bin/pip install \
|
||||
-e /opt/certbot/src/acme \
|
||||
-e /opt/certbot/src \
|
||||
-e /opt/certbot/src/certbot-apache \
|
||||
-e /opt/certbot/src/certbot-nginx \
|
||||
-e /opt/certbot/src/certbot-compatibility-test
|
||||
/opt/certbot/venv/bin/pip install -U pip
|
||||
ENV PATH /opt/certbot/venv/bin:$PATH
|
||||
RUN /opt/certbot/src/tools/pip_install_editable.sh \
|
||||
/opt/certbot/src/acme \
|
||||
/opt/certbot/src \
|
||||
/opt/certbot/src/certbot-apache \
|
||||
/opt/certbot/src/certbot-nginx \
|
||||
/opt/certbot/src/certbot-compatibility-test
|
||||
|
||||
# install in editable mode (-e) to save space: it's not possible to
|
||||
# "rm -rf /opt/certbot/src" (it's stays in the underlaying image);
|
||||
|
|
@ -46,5 +48,3 @@ RUN virtualenv --no-site-packages -p python2 /opt/certbot/venv && \
|
|||
# bash" and investigate, apply patches, etc.
|
||||
|
||||
WORKDIR /opt/certbot/src/certbot-compatibility-test/certbot_compatibility_test/testdata
|
||||
|
||||
ENV PATH /opt/certbot/venv/bin:$PATH
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'certbot',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -4,15 +4,17 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme=={0}'.format(version),
|
||||
'certbot=={0}'.format(version),
|
||||
'google-api-python-client',
|
||||
# 1.5 is the first version that supports oauth2client>=2.0
|
||||
'google-api-python-client>=1.5',
|
||||
'mock',
|
||||
'oauth2client',
|
||||
# for oauth2client.service_account.ServiceAccountCredentials
|
||||
'oauth2client>=2.0',
|
||||
# For pkg_resources. >=1.0 so pip resolves it to a version cryptography
|
||||
# will tolerate; see #2599:
|
||||
'setuptools>=1.0',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import sys
|
|||
from distutils.core import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'acme=={0}'.format(version),
|
||||
|
|
|
|||
|
|
@ -87,8 +87,6 @@ class NginxConfigurator(common.Plugin):
|
|||
|
||||
description = "Nginx Web Server plugin - Alpha"
|
||||
|
||||
hidden = True
|
||||
|
||||
DEFAULT_LISTEN_PORT = '80'
|
||||
|
||||
@classmethod
|
||||
|
|
@ -198,16 +196,10 @@ class NginxConfigurator(common.Plugin):
|
|||
cert_directives = [['\n', 'ssl_certificate', ' ', fullchain_path],
|
||||
['\n', 'ssl_certificate_key', ' ', key_path]]
|
||||
|
||||
try:
|
||||
self.parser.add_server_directives(vhost,
|
||||
cert_directives, replace=True)
|
||||
logger.info("Deployed Certificate to VirtualHost %s for %s",
|
||||
vhost.filep, vhost.names)
|
||||
except errors.MisconfigurationError as error:
|
||||
logger.debug(error)
|
||||
# Presumably break here so that the virtualhost is not modified
|
||||
raise errors.PluginError("Cannot find a cert or key directive in {0} for {1}. "
|
||||
"VirtualHost was not modified.".format(vhost.filep, vhost.names))
|
||||
self.parser.add_server_directives(vhost,
|
||||
cert_directives, replace=True)
|
||||
logger.info("Deployed Certificate to VirtualHost %s for %s",
|
||||
vhost.filep, vhost.names)
|
||||
|
||||
self.save_notes += ("Changed vhost at %s with addresses of %s\n" %
|
||||
(vhost.filep,
|
||||
|
|
|
|||
|
|
@ -278,8 +278,8 @@ class NginxParser(object):
|
|||
|
||||
This method modifies vhost to be fully consistent with the new directives.
|
||||
|
||||
..note :: If replace is True, this raises a misconfiguration error
|
||||
if the directive does not already exist.
|
||||
..note :: If replace is True and the directive already exists, the first
|
||||
instance will be replaced. Otherwise, the directive is added.
|
||||
..note :: If replace is False nothing gets added if an identical
|
||||
block exists already.
|
||||
|
||||
|
|
@ -464,8 +464,9 @@ def _add_directives(block, directives, replace):
|
|||
When replace=False, it's an error to try and add a directive that already
|
||||
exists in the config block with a conflicting value.
|
||||
|
||||
When replace=True, a directive with the same name MUST already exist in the
|
||||
config block, and the first instance will be replaced.
|
||||
When replace=True and a directive with the same name already exists in the
|
||||
config block, the first instance will be replaced. Otherwise, the directive
|
||||
will be added to the config block.
|
||||
|
||||
..todo :: Find directives that are in included files.
|
||||
|
||||
|
|
@ -547,49 +548,46 @@ def _add_directive(block, directive, replace):
|
|||
location = find_location(directive)
|
||||
|
||||
if replace:
|
||||
if location is None:
|
||||
raise errors.MisconfigurationError(
|
||||
'expected directive for {0} in the Nginx '
|
||||
'config but did not find it.'.format(directive[0]))
|
||||
block[location] = directive
|
||||
_comment_directive(block, location)
|
||||
else:
|
||||
# Append directive. Fail if the name is not a repeatable directive name,
|
||||
# and there is already a copy of that directive with a different value
|
||||
# in the config file.
|
||||
if location is not None:
|
||||
block[location] = directive
|
||||
_comment_directive(block, location)
|
||||
return
|
||||
# Append directive. Fail if the name is not a repeatable directive name,
|
||||
# and there is already a copy of that directive with a different value
|
||||
# in the config file.
|
||||
|
||||
# handle flat include files
|
||||
# handle flat include files
|
||||
|
||||
directive_name = directive[0]
|
||||
def can_append(loc, dir_name):
|
||||
""" Can we append this directive to the block? """
|
||||
return loc is None or (isinstance(dir_name, str) and dir_name in REPEATABLE_DIRECTIVES)
|
||||
directive_name = directive[0]
|
||||
def can_append(loc, dir_name):
|
||||
""" Can we append this directive to the block? """
|
||||
return loc is None or (isinstance(dir_name, str) and dir_name in REPEATABLE_DIRECTIVES)
|
||||
|
||||
err_fmt = 'tried to insert directive "{0}" but found conflicting "{1}".'
|
||||
err_fmt = 'tried to insert directive "{0}" but found conflicting "{1}".'
|
||||
|
||||
# Give a better error message about the specific directive than Nginx's "fail to restart"
|
||||
if directive_name == INCLUDE:
|
||||
# in theory, we might want to do this recursively, but in practice, that's really not
|
||||
# necessary because we know what file we're talking about (and if we don't recurse, we
|
||||
# just give a worse error message)
|
||||
included_directives = _parse_ssl_options(directive[1])
|
||||
# Give a better error message about the specific directive than Nginx's "fail to restart"
|
||||
if directive_name == INCLUDE:
|
||||
# in theory, we might want to do this recursively, but in practice, that's really not
|
||||
# necessary because we know what file we're talking about (and if we don't recurse, we
|
||||
# just give a worse error message)
|
||||
included_directives = _parse_ssl_options(directive[1])
|
||||
|
||||
for included_directive in included_directives:
|
||||
included_dir_loc = find_location(included_directive)
|
||||
included_dir_name = included_directive[0]
|
||||
if not is_whitespace_or_comment(included_directive) \
|
||||
and not can_append(included_dir_loc, included_dir_name):
|
||||
if block[included_dir_loc] != included_directive:
|
||||
raise errors.MisconfigurationError(err_fmt.format(included_directive,
|
||||
block[included_dir_loc]))
|
||||
else:
|
||||
_comment_out_directive(block, included_dir_loc, directive[1])
|
||||
for included_directive in included_directives:
|
||||
included_dir_loc = find_location(included_directive)
|
||||
included_dir_name = included_directive[0]
|
||||
if not is_whitespace_or_comment(included_directive) \
|
||||
and not can_append(included_dir_loc, included_dir_name):
|
||||
if block[included_dir_loc] != included_directive:
|
||||
raise errors.MisconfigurationError(err_fmt.format(included_directive,
|
||||
block[included_dir_loc]))
|
||||
else:
|
||||
_comment_out_directive(block, included_dir_loc, directive[1])
|
||||
|
||||
if can_append(location, directive_name):
|
||||
block.append(directive)
|
||||
_comment_directive(block, len(block) - 1)
|
||||
elif block[location] != directive:
|
||||
raise errors.MisconfigurationError(err_fmt.format(directive, block[location]))
|
||||
if can_append(location, directive_name):
|
||||
block.append(directive)
|
||||
_comment_directive(block, len(block) - 1)
|
||||
elif block[location] != directive:
|
||||
raise errors.MisconfigurationError(err_fmt.format(directive, block[location]))
|
||||
|
||||
def _apply_global_addr_ssl(addr_to_ssl, parsed_server):
|
||||
"""Apply global sslishness information to the parsed server block
|
||||
|
|
|
|||
|
|
@ -273,11 +273,16 @@ class NginxParserTest(util.NginxTest): #pylint: disable=too-many-public-methods
|
|||
['server_name', 'example.*'], []
|
||||
]]])
|
||||
mock_vhost.names = set(['foobar.com', 'example.*'])
|
||||
self.assertRaises(errors.MisconfigurationError,
|
||||
nparser.add_server_directives,
|
||||
mock_vhost,
|
||||
[['ssl_certificate', 'cert.pem']],
|
||||
replace=True)
|
||||
nparser.add_server_directives(
|
||||
mock_vhost, [['ssl_certificate', 'cert.pem']], replace=True)
|
||||
self.assertEqual(
|
||||
nparser.parsed[filep],
|
||||
[[['server'], [['listen', '69.50.225.155:9000'],
|
||||
['listen', '127.0.0.1'],
|
||||
['server_name', 'foobar.com'], ['#', COMMENT],
|
||||
['server_name', 'example.*'], [],
|
||||
['ssl_certificate', 'cert.pem'], ['#', COMMENT], [],
|
||||
]]])
|
||||
|
||||
def test_get_best_match(self):
|
||||
target_name = 'www.eff.org'
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
|||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.17.0.dev0'
|
||||
version = '0.18.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Certbot client."""
|
||||
|
||||
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
|
||||
__version__ = '0.17.0.dev0'
|
||||
__version__ = '0.18.0.dev0'
|
||||
|
|
|
|||
|
|
@ -873,14 +873,21 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis
|
|||
metavar="DOMAIN", action=_DomainsAction, default=[],
|
||||
help="Domain names to apply. For multiple domains you can use "
|
||||
"multiple -d flags or enter a comma separated list of domains "
|
||||
"as a parameter. (default: Ask)")
|
||||
"as a parameter. The first provided domain will be used in "
|
||||
"some software user interfaces and file paths for the "
|
||||
"certificate and related material unless otherwise "
|
||||
"specified or you already have a certificate for the same "
|
||||
"domains. (default: Ask)")
|
||||
helpful.add(
|
||||
[None, "run", "certonly", "manage", "delete", "certificates"],
|
||||
"--cert-name", dest="certname",
|
||||
metavar="CERTNAME", default=None,
|
||||
help="Certificate name to apply. Only one certificate name can be used "
|
||||
"per Certbot run. To see certificate names, run 'certbot certificates'. "
|
||||
"When creating a new certificate, specifies the new certificate's name.")
|
||||
help="Certificate name to apply. This name is used by Certbot for housekeeping "
|
||||
"and in file paths; it doesn't affect the content of the certificate itself. "
|
||||
"To see certificate names, run 'certbot certificates'. "
|
||||
"When creating a new certificate, specifies the new certificate's name. "
|
||||
"(default: the first provided domain or the name of an existing "
|
||||
"certificate on your system for the same domains)")
|
||||
helpful.add(
|
||||
[None, "testing", "renew", "certonly"],
|
||||
"--dry-run", action="store_true", dest="dry_run",
|
||||
|
|
@ -1145,15 +1152,21 @@ def _create_subparsers(helpful):
|
|||
'(default: {0}). The flags encoded in the user agent are: '
|
||||
'--duplicate, --force-renew, --allow-subset-of-names, -n, and '
|
||||
'whether any hooks are set.'.format(sample_user_agent()))
|
||||
helpful.add(
|
||||
None, "--user-agent-comment", default=None, type=_user_agent_comment_type,
|
||||
help="Add a comment to the default user agent string. May be used when repackaging Certbot "
|
||||
"or calling it from another tool to allow additional statistical data to be collected."
|
||||
" Ignored if --user-agent is set. (Example: Foo-Wrapper/1.0)")
|
||||
helpful.add("certonly",
|
||||
"--csr", type=read_file,
|
||||
help="Path to a Certificate Signing Request (CSR) in DER or PEM format."
|
||||
" Currently --csr only works with the 'certonly' subcommand.")
|
||||
helpful.add("revoke",
|
||||
"--reason", dest="reason",
|
||||
choices=CaseInsensitiveList(constants.REVOCATION_REASONS.keys()),
|
||||
choices=CaseInsensitiveList(sorted(constants.REVOCATION_REASONS,
|
||||
key=constants.REVOCATION_REASONS.get)),
|
||||
action=_EncodeReasonAction, default=0,
|
||||
help="Specify reason for revoking certificate.")
|
||||
help="Specify reason for revoking certificate. (default: unspecified)")
|
||||
helpful.add("rollback",
|
||||
"--checkpoints", type=int, metavar="N",
|
||||
default=flag_default("rollback_checkpoints"),
|
||||
|
|
@ -1360,6 +1373,10 @@ def parse_preferred_challenges(pref_challs):
|
|||
"Unrecognized challenges: {0}".format(unrecognized))
|
||||
return challs
|
||||
|
||||
def _user_agent_comment_type(value):
|
||||
if "(" in value or ")" in value:
|
||||
raise argparse.ArgumentTypeError("may not contain parentheses")
|
||||
return value
|
||||
|
||||
class _DeployHookAction(argparse.Action):
|
||||
"""Action class for parsing deploy hooks."""
|
||||
|
|
|
|||
|
|
@ -58,11 +58,12 @@ def determine_user_agent(config):
|
|||
# policy, talk to a core Certbot team member before making any
|
||||
# changes here.
|
||||
if config.user_agent is None:
|
||||
ua = ("CertbotACMEClient/{0} ({1}; {2}) Authenticator/{3} Installer/{4} "
|
||||
ua = ("CertbotACMEClient/{0} ({1}; {2}{8}) Authenticator/{3} Installer/{4} "
|
||||
"({5}; flags: {6}) Py/{7}")
|
||||
ua = ua.format(certbot.__version__, cli.cli_command, util.get_os_info_ua(),
|
||||
config.authenticator, config.installer, config.verb,
|
||||
ua_flags(config), platform.python_version())
|
||||
ua_flags(config), platform.python_version(),
|
||||
"; " + config.user_agent_comment if config.user_agent_comment else "")
|
||||
else:
|
||||
ua = config.user_agent
|
||||
return ua
|
||||
|
|
|
|||
|
|
@ -645,6 +645,7 @@ def renew_cert(config, plugins, lineage):
|
|||
except errors.PluginSelectionError as e:
|
||||
logger.info("Could not choose appropriate plugin: %s", e)
|
||||
raise
|
||||
|
||||
le_client = _init_le_client(config, auth, installer)
|
||||
|
||||
_get_and_save_cert(le_client, config, lineage=lineage)
|
||||
|
|
@ -673,6 +674,7 @@ def certonly(config, plugins):
|
|||
except errors.PluginSelectionError as e:
|
||||
logger.info("Could not choose appropriate plugin: %s", e)
|
||||
raise
|
||||
|
||||
le_client = _init_le_client(config, auth, installer)
|
||||
|
||||
if config.csr:
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ class TLSSNI01Test(unittest.TestCase):
|
|||
achall.chall.encode.return_value = "token"
|
||||
key = test_util.load_pyopenssl_private_key("rsa512_key.pem")
|
||||
achall.response_and_validation.return_value = (
|
||||
response, (test_util.load_cert("cert.pem"), key))
|
||||
response, (test_util.load_cert("cert_512.pem"), key))
|
||||
|
||||
with mock.patch("certbot.plugins.common.open",
|
||||
mock_open, create=True):
|
||||
|
|
@ -215,7 +215,7 @@ class TLSSNI01Test(unittest.TestCase):
|
|||
# pylint: disable=no-member
|
||||
mock_open.assert_called_once_with(self.sni.get_cert_path(achall), "wb")
|
||||
mock_open.return_value.write.assert_called_once_with(
|
||||
test_util.load_vector("cert.pem"))
|
||||
test_util.load_vector("cert_512.pem"))
|
||||
mock_safe_open.assert_called_once_with(
|
||||
self.sni.get_key_path(achall), "wb", chmod=0o400)
|
||||
mock_safe_open.return_value.write.assert_called_once_with(
|
||||
|
|
|
|||
|
|
@ -108,11 +108,19 @@ def choose_plugin(prepared, question):
|
|||
opts = [plugin_ep.description_with_name +
|
||||
(" [Misconfigured]" if plugin_ep.misconfigured else "")
|
||||
for plugin_ep in prepared]
|
||||
names = set(plugin_ep.name for plugin_ep in prepared)
|
||||
|
||||
while True:
|
||||
disp = z_util(interfaces.IDisplay)
|
||||
code, index = disp.menu(
|
||||
question, opts, force_interactive=True)
|
||||
if "CERTBOT_AUTO" in os.environ and names == set(("apache", "nginx")):
|
||||
# The possibility of being offered exactly apache and nginx here
|
||||
# is new interactivity brought by https://github.com/certbot/certbot/issues/4079,
|
||||
# so set apache as a default for those kinds of non-interactive use
|
||||
# (the user will get a warning to set --non-interactive or --force-interactive)
|
||||
apache_idx = [n for n, p in enumerate(prepared) if p.name == "apache"][0]
|
||||
code, index = disp.menu(question, opts, default=apache_idx)
|
||||
else:
|
||||
code, index = disp.menu(question, opts, force_interactive=True)
|
||||
|
||||
if code == display_util.OK:
|
||||
plugin_ep = prepared[index]
|
||||
|
|
@ -134,6 +142,8 @@ def record_chosen_plugins(config, plugins, auth, inst):
|
|||
"Update the config entries to reflect the plugins we actually selected."
|
||||
config.authenticator = plugins.find_init(auth).name if auth else "None"
|
||||
config.installer = plugins.find_init(inst).name if inst else "None"
|
||||
logger.info("Plugins selected: Authenticator %s, Installer %s",
|
||||
config.authenticator, config.installer)
|
||||
|
||||
|
||||
def choose_configurator_plugins(config, plugins, verb):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
"""Tests for letsencrypt.plugins.selection"""
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
|
|
@ -115,6 +116,7 @@ class ChoosePluginTest(unittest.TestCase):
|
|||
False))
|
||||
self.mock_apache = mock.Mock(
|
||||
description_with_name="a", misconfigured=True)
|
||||
self.mock_apache.name = "apache"
|
||||
self.mock_stand = mock.Mock(
|
||||
description_with_name="s", misconfigured=False)
|
||||
self.mock_stand.init().more_info.return_value = "standalone"
|
||||
|
|
@ -146,3 +148,26 @@ class ChoosePluginTest(unittest.TestCase):
|
|||
def test_no_choice(self, mock_util):
|
||||
mock_util().menu.return_value = (display_util.CANCEL, 0)
|
||||
self.assertTrue(self._call() is None)
|
||||
|
||||
@test_util.patch_get_utility("certbot.plugins.selection.z_util")
|
||||
def test_new_interaction_avoidance(self, mock_util):
|
||||
mock_nginx = mock.Mock(
|
||||
description_with_name="n", misconfigured=False)
|
||||
mock_nginx.init().more_info.return_value = "nginx plugin"
|
||||
mock_nginx.name = "nginx"
|
||||
self.plugins[1] = mock_nginx
|
||||
mock_util().menu.return_value = (display_util.CANCEL, 0)
|
||||
|
||||
unset_cb_auto = os.environ.get("CERTBOT_AUTO") is None
|
||||
if unset_cb_auto:
|
||||
os.environ["CERTBOT_AUTO"] = "foo"
|
||||
try:
|
||||
self._call()
|
||||
finally:
|
||||
if unset_cb_auto:
|
||||
del os.environ["CERTBOT_AUTO"]
|
||||
|
||||
self.assertTrue("default" in mock_util().menu.call_args[1])
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main() # pragma: no cover
|
||||
|
|
|
|||
|
|
@ -389,14 +389,16 @@ def handle_renewal_request(config):
|
|||
disp = zope.component.getUtility(interfaces.IDisplay)
|
||||
disp.notification("Processing " + renewal_file, pause=False)
|
||||
lineage_config = copy.deepcopy(config)
|
||||
lineagename = storage.lineagename_for_filename(renewal_file)
|
||||
|
||||
# Note that this modifies config (to add back the configuration
|
||||
# elements from within the renewal configuration file).
|
||||
try:
|
||||
renewal_candidate = _reconstitute(lineage_config, renewal_file)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
logger.warning("Renewal configuration file %s produced an "
|
||||
"unexpected error: %s. Skipping.", renewal_file, e)
|
||||
logger.warning("Renewal configuration file %s (cert: %s) "
|
||||
"produced an unexpected error: %s. Skipping.",
|
||||
renewal_file, lineagename, e)
|
||||
logger.debug("Traceback was:\n%s", traceback.format_exc())
|
||||
parse_failures.append(renewal_file)
|
||||
continue
|
||||
|
|
@ -422,8 +424,9 @@ def handle_renewal_request(config):
|
|||
renew_skipped.append(renewal_candidate.fullchain)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
# obtain_cert (presumably) encountered an unanticipated problem.
|
||||
logger.warning("Attempting to renew cert from %s produced an "
|
||||
"unexpected error: %s. Skipping.", renewal_file, e)
|
||||
logger.warning("Attempting to renew cert (%s) from %s produced an "
|
||||
"unexpected error: %s. Skipping.", lineagename,
|
||||
renewal_file, e)
|
||||
logger.debug("Traceback was:\n%s", traceback.format_exc())
|
||||
renew_failures.append(renewal_candidate.fullchain)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,12 +14,10 @@ from acme import messages
|
|||
|
||||
from certbot import errors
|
||||
|
||||
from certbot.tests import util
|
||||
|
||||
from certbot.tests.util import TempDirTestCase
|
||||
import certbot.tests.util as test_util
|
||||
|
||||
|
||||
KEY = jose.JWKRSA.load(util.load_vector("rsa512_key_2.pem"))
|
||||
KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem"))
|
||||
|
||||
|
||||
class AccountTest(unittest.TestCase):
|
||||
|
|
@ -48,22 +46,19 @@ class AccountTest(unittest.TestCase):
|
|||
|
||||
def test_id(self):
|
||||
self.assertEqual(
|
||||
self.acc.id, "bca5889f66457d5b62fbba7b25f9ab6f")
|
||||
self.acc.id, "7adac10320f585ddf118429c0c4af2cd")
|
||||
|
||||
def test_slug(self):
|
||||
self.assertEqual(
|
||||
self.acc.slug, "test.certbot.org@2015-07-04T14:04:10Z (bca5)")
|
||||
self.acc.slug, "test.certbot.org@2015-07-04T14:04:10Z (7ada)")
|
||||
|
||||
def test_repr(self):
|
||||
self.assertTrue(repr(self.acc).startswith(
|
||||
"<Account(i_am_a_regr, bca5889f66457d5b62fbba7b25f9ab6f, Meta("))
|
||||
"<Account(i_am_a_regr, 7adac10320f585ddf118429c0c4af2cd, Meta("))
|
||||
|
||||
class ReportNewAccountTest(unittest.TestCase):
|
||||
class ReportNewAccountTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.account.report_new_account."""
|
||||
|
||||
def setUp(self):
|
||||
self.config = mock.MagicMock(config_dir="/etc/letsencrypt")
|
||||
|
||||
def _call(self):
|
||||
from certbot.account import report_new_account
|
||||
report_new_account(self.config)
|
||||
|
|
@ -98,14 +93,12 @@ class AccountMemoryStorageTest(unittest.TestCase):
|
|||
self.assertEqual([account], self.storage.find_all())
|
||||
|
||||
|
||||
class AccountFileStorageTest(TempDirTestCase):
|
||||
class AccountFileStorageTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.account.AccountFileStorage."""
|
||||
|
||||
def setUp(self):
|
||||
super(AccountFileStorageTest, self).setUp()
|
||||
|
||||
self.config = mock.MagicMock(
|
||||
accounts_dir=os.path.join(self.tempdir, "accounts"))
|
||||
from certbot.account import AccountFileStorage
|
||||
self.storage = AccountFileStorage(self.config)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,58 +18,50 @@ from certbot.storage import ALL_FOUR
|
|||
from certbot.tests import storage_test
|
||||
from certbot.tests import util as test_util
|
||||
|
||||
from certbot.tests.util import TempDirTestCase
|
||||
|
||||
|
||||
class BaseCertManagerTest(TempDirTestCase):
|
||||
class BaseCertManagerTest(test_util.ConfigTestCase):
|
||||
"""Base class for setting up Cert Manager tests.
|
||||
"""
|
||||
def setUp(self):
|
||||
super(BaseCertManagerTest, self).setUp()
|
||||
|
||||
os.makedirs(os.path.join(self.tempdir, "renewal"))
|
||||
|
||||
self.cli_config = configuration.NamespaceConfig(mock.MagicMock(
|
||||
config_dir=self.tempdir,
|
||||
work_dir=self.tempdir,
|
||||
logs_dir=self.tempdir,
|
||||
quiet=False,
|
||||
))
|
||||
self.config.quiet = False
|
||||
os.makedirs(self.config.renewal_configs_dir)
|
||||
|
||||
self.domains = {
|
||||
"example.org": None,
|
||||
"other.com": os.path.join(self.tempdir, "specialarchive")
|
||||
"other.com": os.path.join(self.config.config_dir, "specialarchive")
|
||||
}
|
||||
self.configs = dict((domain, self._set_up_config(domain, self.domains[domain]))
|
||||
self.config_files = dict((domain, self._set_up_config(domain, self.domains[domain]))
|
||||
for domain in self.domains)
|
||||
|
||||
# We also create a file that isn't a renewal config in the same
|
||||
# location to test that logic that reads in all-and-only renewal
|
||||
# configs will ignore it and NOT attempt to parse it.
|
||||
junk = open(os.path.join(self.tempdir, "renewal", "IGNORE.THIS"), "w")
|
||||
junk = open(os.path.join(self.config.renewal_configs_dir, "IGNORE.THIS"), "w")
|
||||
junk.write("This file should be ignored!")
|
||||
junk.close()
|
||||
|
||||
def _set_up_config(self, domain, custom_archive):
|
||||
# TODO: maybe provide NamespaceConfig.make_dirs?
|
||||
# TODO: main() should create those dirs, c.f. #902
|
||||
os.makedirs(os.path.join(self.tempdir, "live", domain))
|
||||
config = configobj.ConfigObj()
|
||||
os.makedirs(os.path.join(self.config.live_dir, domain))
|
||||
config_file = configobj.ConfigObj()
|
||||
|
||||
if custom_archive is not None:
|
||||
os.makedirs(custom_archive)
|
||||
config["archive_dir"] = custom_archive
|
||||
config_file["archive_dir"] = custom_archive
|
||||
else:
|
||||
os.makedirs(os.path.join(self.tempdir, "archive", domain))
|
||||
os.makedirs(os.path.join(self.config.default_archive_dir, domain))
|
||||
|
||||
for kind in ALL_FOUR:
|
||||
config[kind] = os.path.join(self.tempdir, "live", domain,
|
||||
config_file[kind] = os.path.join(self.config.live_dir, domain,
|
||||
kind + ".pem")
|
||||
|
||||
config.filename = os.path.join(self.tempdir, "renewal",
|
||||
config_file.filename = os.path.join(self.config.renewal_configs_dir,
|
||||
domain + ".conf")
|
||||
config.write()
|
||||
return config
|
||||
config_file.write()
|
||||
return config_file
|
||||
|
||||
|
||||
class UpdateLiveSymlinksTest(BaseCertManagerTest):
|
||||
|
|
@ -86,27 +78,27 @@ class UpdateLiveSymlinksTest(BaseCertManagerTest):
|
|||
if custom_archive is not None:
|
||||
archive_dir_path = custom_archive
|
||||
else:
|
||||
archive_dir_path = os.path.join(self.tempdir, "archive", domain)
|
||||
archive_dir_path = os.path.join(self.config.default_archive_dir, domain)
|
||||
archive_paths[domain] = dict((kind,
|
||||
os.path.join(archive_dir_path, kind + "1.pem")) for kind in ALL_FOUR)
|
||||
for kind in ALL_FOUR:
|
||||
live_path = self.configs[domain][kind]
|
||||
live_path = self.config_files[domain][kind]
|
||||
archive_path = archive_paths[domain][kind]
|
||||
open(archive_path, 'a').close()
|
||||
# path is incorrect but base must be correct
|
||||
os.symlink(os.path.join(self.tempdir, kind + "1.pem"), live_path)
|
||||
os.symlink(os.path.join(self.config.config_dir, kind + "1.pem"), live_path)
|
||||
|
||||
# run update symlinks
|
||||
cert_manager.update_live_symlinks(self.cli_config)
|
||||
cert_manager.update_live_symlinks(self.config)
|
||||
|
||||
# check that symlinks go where they should
|
||||
prev_dir = os.getcwd()
|
||||
try:
|
||||
for domain in self.domains:
|
||||
for kind in ALL_FOUR:
|
||||
os.chdir(os.path.dirname(self.configs[domain][kind]))
|
||||
os.chdir(os.path.dirname(self.config_files[domain][kind]))
|
||||
self.assertEqual(
|
||||
os.path.realpath(os.readlink(self.configs[domain][kind])),
|
||||
os.path.realpath(os.readlink(self.config_files[domain][kind])),
|
||||
os.path.realpath(archive_paths[domain][kind]))
|
||||
finally:
|
||||
os.chdir(prev_dir)
|
||||
|
|
@ -121,9 +113,9 @@ class DeleteTest(storage_test.BaseRenewableCertTest):
|
|||
def test_delete(self, mock_delete_files, mock_lineage_for_certname, unused_get_utility):
|
||||
"""Test delete"""
|
||||
mock_lineage_for_certname.return_value = self.test_rc
|
||||
self.cli_config.certname = "example.org"
|
||||
self.config.certname = "example.org"
|
||||
from certbot import cert_manager
|
||||
cert_manager.delete(self.cli_config)
|
||||
cert_manager.delete(self.config)
|
||||
self.assertTrue(mock_delete_files.called)
|
||||
|
||||
|
||||
|
|
@ -137,15 +129,15 @@ class CertificatesTest(BaseCertManagerTest):
|
|||
@mock.patch('certbot.cert_manager.logger')
|
||||
@test_util.patch_get_utility()
|
||||
def test_certificates_parse_fail(self, mock_utility, mock_logger):
|
||||
self._certificates(self.cli_config)
|
||||
self._certificates(self.config)
|
||||
self.assertTrue(mock_logger.warning.called) #pylint: disable=no-member
|
||||
self.assertTrue(mock_utility.called)
|
||||
|
||||
@mock.patch('certbot.cert_manager.logger')
|
||||
@test_util.patch_get_utility()
|
||||
def test_certificates_quiet(self, mock_utility, mock_logger):
|
||||
self.cli_config.quiet = True
|
||||
self._certificates(self.cli_config)
|
||||
self.config.quiet = True
|
||||
self._certificates(self.config)
|
||||
self.assertFalse(mock_utility.notification.called)
|
||||
self.assertTrue(mock_logger.warning.called) #pylint: disable=no-member
|
||||
|
||||
|
|
@ -158,7 +150,7 @@ class CertificatesTest(BaseCertManagerTest):
|
|||
mock_utility, mock_logger, mock_verifier):
|
||||
mock_verifier.return_value = None
|
||||
mock_report.return_value = ""
|
||||
self._certificates(self.cli_config)
|
||||
self._certificates(self.config)
|
||||
self.assertFalse(mock_logger.warning.called) #pylint: disable=no-member
|
||||
self.assertTrue(mock_report.called)
|
||||
self.assertTrue(mock_utility.called)
|
||||
|
|
@ -167,20 +159,19 @@ class CertificatesTest(BaseCertManagerTest):
|
|||
@mock.patch('certbot.cert_manager.logger')
|
||||
@test_util.patch_get_utility()
|
||||
def test_certificates_no_files(self, mock_utility, mock_logger):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
|
||||
cli_config = configuration.NamespaceConfig(mock.MagicMock(
|
||||
config_dir=tempdir,
|
||||
work_dir=tempdir,
|
||||
logs_dir=tempdir,
|
||||
quiet=False,
|
||||
empty_tempdir = tempfile.mkdtemp()
|
||||
empty_config = configuration.NamespaceConfig(mock.MagicMock(
|
||||
config_dir=os.path.join(empty_tempdir, "config"),
|
||||
work_dir=os.path.join(empty_tempdir, "work"),
|
||||
logs_dir=os.path.join(empty_tempdir, "logs"),
|
||||
quiet=False
|
||||
))
|
||||
|
||||
os.makedirs(os.path.join(tempdir, "renewal"))
|
||||
self._certificates(cli_config)
|
||||
os.makedirs(empty_config.renewal_configs_dir)
|
||||
self._certificates(empty_config)
|
||||
self.assertFalse(mock_logger.warning.called) #pylint: disable=no-member
|
||||
self.assertTrue(mock_utility.called)
|
||||
shutil.rmtree(tempdir)
|
||||
shutil.rmtree(empty_tempdir)
|
||||
|
||||
@mock.patch('certbot.cert_manager.ocsp.RevocationChecker.ocsp_revoked')
|
||||
def test_report_human_readable(self, mock_revoked):
|
||||
|
|
@ -261,7 +252,7 @@ class SearchLineagesTest(BaseCertManagerTest):
|
|||
mock_renewable_cert.side_effect = errors.CertStorageError
|
||||
from certbot import cert_manager
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(cert_manager._search_lineages(self.cli_config, lambda x: x, "check"),
|
||||
self.assertEqual(cert_manager._search_lineages(self.config, lambda x: x, "check"),
|
||||
"check")
|
||||
self.assertTrue(mock_make_or_verify_dir.called)
|
||||
|
||||
|
|
@ -278,7 +269,7 @@ class LineageForCertnameTest(BaseCertManagerTest):
|
|||
mock_match = mock.Mock(lineagename="example.com")
|
||||
mock_renewable_cert.return_value = mock_match
|
||||
from certbot import cert_manager
|
||||
self.assertEqual(cert_manager.lineage_for_certname(self.cli_config, "example.com"),
|
||||
self.assertEqual(cert_manager.lineage_for_certname(self.config, "example.com"),
|
||||
mock_match)
|
||||
self.assertTrue(mock_make_or_verify_dir.called)
|
||||
|
||||
|
|
@ -288,7 +279,7 @@ class LineageForCertnameTest(BaseCertManagerTest):
|
|||
mock_make_or_verify_dir):
|
||||
mock_renewal_conf_file.return_value = "other.com.conf"
|
||||
from certbot import cert_manager
|
||||
self.assertEqual(cert_manager.lineage_for_certname(self.cli_config, "example.com"),
|
||||
self.assertEqual(cert_manager.lineage_for_certname(self.config, "example.com"),
|
||||
None)
|
||||
self.assertTrue(mock_make_or_verify_dir.called)
|
||||
|
||||
|
|
@ -298,7 +289,7 @@ class LineageForCertnameTest(BaseCertManagerTest):
|
|||
mock_make_or_verify_dir):
|
||||
mock_renewal_conf_file.side_effect = errors.CertStorageError()
|
||||
from certbot import cert_manager
|
||||
self.assertEqual(cert_manager.lineage_for_certname(self.cli_config, "example.com"),
|
||||
self.assertEqual(cert_manager.lineage_for_certname(self.config, "example.com"),
|
||||
None)
|
||||
self.assertTrue(mock_make_or_verify_dir.called)
|
||||
|
||||
|
|
@ -317,7 +308,7 @@ class DomainsForCertnameTest(BaseCertManagerTest):
|
|||
mock_match.names.return_value = domains
|
||||
mock_renewable_cert.return_value = mock_match
|
||||
from certbot import cert_manager
|
||||
self.assertEqual(cert_manager.domains_for_certname(self.cli_config, "example.com"),
|
||||
self.assertEqual(cert_manager.domains_for_certname(self.config, "example.com"),
|
||||
domains)
|
||||
self.assertTrue(mock_make_or_verify_dir.called)
|
||||
|
||||
|
|
@ -327,7 +318,7 @@ class DomainsForCertnameTest(BaseCertManagerTest):
|
|||
mock_make_or_verify_dir):
|
||||
mock_renewal_conf_file.return_value = "somefile.conf"
|
||||
from certbot import cert_manager
|
||||
self.assertEqual(cert_manager.domains_for_certname(self.cli_config, "other.com"),
|
||||
self.assertEqual(cert_manager.domains_for_certname(self.config, "other.com"),
|
||||
None)
|
||||
self.assertTrue(mock_make_or_verify_dir.called)
|
||||
|
||||
|
|
@ -337,15 +328,8 @@ class RenameLineageTest(BaseCertManagerTest):
|
|||
|
||||
def setUp(self):
|
||||
super(RenameLineageTest, self).setUp()
|
||||
self.mock_config = configuration.NamespaceConfig(
|
||||
namespace=mock.MagicMock(
|
||||
config_dir=self.tempdir,
|
||||
work_dir=self.tempdir,
|
||||
logs_dir=self.tempdir,
|
||||
certname="example.org",
|
||||
new_certname="after",
|
||||
)
|
||||
)
|
||||
self.config.certname = "example.org"
|
||||
self.config.new_certname = "after"
|
||||
|
||||
def _call(self, *args, **kwargs):
|
||||
from certbot import cert_manager
|
||||
|
|
@ -354,81 +338,81 @@ class RenameLineageTest(BaseCertManagerTest):
|
|||
@mock.patch('certbot.storage.renewal_conf_files')
|
||||
@test_util.patch_get_utility()
|
||||
def test_no_certname(self, mock_get_utility, mock_renewal_conf_files):
|
||||
mock_config = mock.Mock(certname=None, new_certname="two")
|
||||
self.config.certname = None
|
||||
self.config.new_certname = "two"
|
||||
|
||||
# if not choices
|
||||
mock_renewal_conf_files.return_value = []
|
||||
self.assertRaises(errors.Error, self._call, mock_config)
|
||||
self.assertRaises(errors.Error, self._call, self.config)
|
||||
|
||||
mock_renewal_conf_files.return_value = ["one.conf"]
|
||||
util_mock = mock.Mock()
|
||||
util_mock.menu.return_value = (display_util.CANCEL, 0)
|
||||
mock_get_utility.return_value = util_mock
|
||||
self.assertRaises(errors.Error, self._call, mock_config)
|
||||
self.assertRaises(errors.Error, self._call, self.config)
|
||||
|
||||
util_mock.menu.return_value = (display_util.OK, -1)
|
||||
self.assertRaises(errors.Error, self._call, mock_config)
|
||||
self.assertRaises(errors.Error, self._call, self.config)
|
||||
|
||||
@test_util.patch_get_utility()
|
||||
def test_no_new_certname(self, mock_get_utility):
|
||||
mock_config = mock.Mock(certname="one", new_certname=None)
|
||||
self.config.certname = "one"
|
||||
self.config.new_certname = None
|
||||
|
||||
util_mock = mock.Mock()
|
||||
util_mock.input.return_value = (display_util.CANCEL, "name")
|
||||
mock_get_utility.return_value = util_mock
|
||||
self.assertRaises(errors.Error, self._call, mock_config)
|
||||
self.assertRaises(errors.Error, self._call, self.config)
|
||||
|
||||
util_mock = mock.Mock()
|
||||
util_mock.input.return_value = (display_util.OK, None)
|
||||
mock_get_utility.return_value = util_mock
|
||||
self.assertRaises(errors.Error, self._call, mock_config)
|
||||
self.assertRaises(errors.Error, self._call, self.config)
|
||||
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch('certbot.cert_manager.lineage_for_certname')
|
||||
def test_no_existing_certname(self, mock_lineage_for_certname, unused_get_utility):
|
||||
mock_config = mock.Mock(certname="one", new_certname="two")
|
||||
self.config.certname = "one"
|
||||
self.config.new_certname = "two"
|
||||
mock_lineage_for_certname.return_value = None
|
||||
self.assertRaises(errors.ConfigurationError,
|
||||
self._call, mock_config)
|
||||
self._call, self.config)
|
||||
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch("certbot.storage.RenewableCert._check_symlinks")
|
||||
def test_rename_cert(self, mock_check, unused_get_utility):
|
||||
mock_check.return_value = True
|
||||
mock_config = self.mock_config
|
||||
self._call(mock_config)
|
||||
self._call(self.config)
|
||||
from certbot import cert_manager
|
||||
updated_lineage = cert_manager.lineage_for_certname(mock_config, mock_config.new_certname)
|
||||
updated_lineage = cert_manager.lineage_for_certname(self.config, self.config.new_certname)
|
||||
self.assertTrue(updated_lineage is not None)
|
||||
self.assertEqual(updated_lineage.lineagename, mock_config.new_certname)
|
||||
self.assertEqual(updated_lineage.lineagename, self.config.new_certname)
|
||||
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch("certbot.storage.RenewableCert._check_symlinks")
|
||||
def test_rename_cert_interactive_certname(self, mock_check, mock_get_utility):
|
||||
mock_check.return_value = True
|
||||
mock_config = self.mock_config
|
||||
mock_config.certname = None
|
||||
self.config.certname = None
|
||||
util_mock = mock.Mock()
|
||||
util_mock.menu.return_value = (display_util.OK, 0)
|
||||
mock_get_utility.return_value = util_mock
|
||||
self._call(mock_config)
|
||||
self._call(self.config)
|
||||
from certbot import cert_manager
|
||||
updated_lineage = cert_manager.lineage_for_certname(mock_config, mock_config.new_certname)
|
||||
updated_lineage = cert_manager.lineage_for_certname(self.config, self.config.new_certname)
|
||||
self.assertTrue(updated_lineage is not None)
|
||||
self.assertEqual(updated_lineage.lineagename, mock_config.new_certname)
|
||||
self.assertEqual(updated_lineage.lineagename, self.config.new_certname)
|
||||
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch("certbot.storage.RenewableCert._check_symlinks")
|
||||
def test_rename_cert_bad_new_certname(self, mock_check, unused_get_utility):
|
||||
mock_check.return_value = True
|
||||
mock_config = self.mock_config
|
||||
|
||||
# for example, don't rename to existing certname
|
||||
mock_config.new_certname = "example.org"
|
||||
self.assertRaises(errors.ConfigurationError, self._call, mock_config)
|
||||
self.config.new_certname = "example.org"
|
||||
self.assertRaises(errors.ConfigurationError, self._call, self.config)
|
||||
|
||||
mock_config.new_certname = "one{0}two".format(os.path.sep)
|
||||
self.assertRaises(errors.ConfigurationError, self._call, mock_config)
|
||||
self.config.new_certname = "one{0}two".format(os.path.sep)
|
||||
self.assertRaises(errors.ConfigurationError, self._call, self.config)
|
||||
|
||||
|
||||
class DuplicativeCertsTest(storage_test.BaseRenewableCertTest):
|
||||
|
|
@ -436,36 +420,36 @@ class DuplicativeCertsTest(storage_test.BaseRenewableCertTest):
|
|||
|
||||
def setUp(self):
|
||||
super(DuplicativeCertsTest, self).setUp()
|
||||
self.config.write()
|
||||
self.config_file.write()
|
||||
self._write_out_ex_kinds()
|
||||
|
||||
@mock.patch('certbot.util.make_or_verify_dir')
|
||||
def test_find_duplicative_names(self, unused_makedir):
|
||||
from certbot.cert_manager import find_duplicative_certs
|
||||
test_cert = test_util.load_vector('cert-san.pem')
|
||||
test_cert = test_util.load_vector('cert-san_512.pem')
|
||||
with open(self.test_rc.cert, 'wb') as f:
|
||||
f.write(test_cert)
|
||||
|
||||
# No overlap at all
|
||||
result = find_duplicative_certs(
|
||||
self.cli_config, ['wow.net', 'hooray.org'])
|
||||
self.config, ['wow.net', 'hooray.org'])
|
||||
self.assertEqual(result, (None, None))
|
||||
|
||||
# Totally identical
|
||||
result = find_duplicative_certs(
|
||||
self.cli_config, ['example.com', 'www.example.com'])
|
||||
self.config, ['example.com', 'www.example.com'])
|
||||
self.assertTrue(result[0].configfile.filename.endswith('example.org.conf'))
|
||||
self.assertEqual(result[1], None)
|
||||
|
||||
# Superset
|
||||
result = find_duplicative_certs(
|
||||
self.cli_config, ['example.com', 'www.example.com', 'something.new'])
|
||||
self.config, ['example.com', 'www.example.com', 'something.new'])
|
||||
self.assertEqual(result[0], None)
|
||||
self.assertTrue(result[1].configfile.filename.endswith('example.org.conf'))
|
||||
|
||||
# Partial overlap doesn't count
|
||||
result = find_duplicative_certs(
|
||||
self.cli_config, ['example.com', 'something.new'])
|
||||
self.config, ['example.com', 'something.new'])
|
||||
self.assertEqual(result, (None, None))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -18,23 +18,16 @@ import certbot.tests.util as test_util
|
|||
|
||||
|
||||
KEY = test_util.load_vector("rsa512_key.pem")
|
||||
CSR_SAN = test_util.load_vector("csr-san.pem")
|
||||
CSR_SAN = test_util.load_vector("csr-san_512.pem")
|
||||
|
||||
|
||||
class ConfigHelper(object):
|
||||
"""Creates a dummy object to imitate a namespace object
|
||||
|
||||
Example: cfg = ConfigHelper(redirect=True, hsts=False, uir=False)
|
||||
will result in: cfg.redirect=True, cfg.hsts=False, etc.
|
||||
"""
|
||||
def __init__(self, **kwds):
|
||||
self.__dict__.update(kwds)
|
||||
|
||||
class RegisterTest(unittest.TestCase):
|
||||
class RegisterTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.client.register."""
|
||||
|
||||
def setUp(self):
|
||||
self.config = mock.MagicMock(rsa_key_size=1024, register_unsafely_without_email=False)
|
||||
super(RegisterTest, self).setUp()
|
||||
self.config.rsa_key_size = 1024
|
||||
self.config.register_unsafely_without_email = False
|
||||
self.account_storage = account.AccountMemoryStorage()
|
||||
self.tos_cb = mock.MagicMock()
|
||||
|
||||
|
|
@ -116,14 +109,12 @@ class RegisterTest(unittest.TestCase):
|
|||
self.assertFalse(mock_handle.called)
|
||||
|
||||
|
||||
class ClientTestCommon(unittest.TestCase):
|
||||
class ClientTestCommon(test_util.ConfigTestCase):
|
||||
"""Common base class for certbot.client.Client tests."""
|
||||
def setUp(self):
|
||||
self.config = mock.MagicMock(
|
||||
no_verify_ssl=False,
|
||||
config_dir="/etc/letsencrypt",
|
||||
work_dir="/var/lib/letsencrypt",
|
||||
allow_subset_of_names=False)
|
||||
super(ClientTestCommon, self).setUp()
|
||||
self.config.no_verify_ssl = False
|
||||
self.config.allow_subset_of_names = False
|
||||
|
||||
# pylint: disable=star-args
|
||||
self.account = mock.MagicMock(**{"key.pem": KEY})
|
||||
|
|
@ -143,7 +134,6 @@ class ClientTest(ClientTestCommon):
|
|||
super(ClientTest, self).setUp()
|
||||
|
||||
self.config.allow_subset_of_names = False
|
||||
self.config.config_dir = "/etc/letsencrypt"
|
||||
self.config.dry_run = False
|
||||
self.eg_domains = ["example.com", "www.example.com"]
|
||||
|
||||
|
|
@ -262,8 +252,8 @@ class ClientTest(ClientTestCommon):
|
|||
mock_crypto.make_key.return_value = mock.sentinel.key_pem
|
||||
key = util.Key(file=None, pem=mock.sentinel.key_pem)
|
||||
|
||||
with mock.patch.object(self.client.config, 'dry_run', new=True):
|
||||
self._test_obtain_certificate_common(key, csr)
|
||||
self.client.config.dry_run = True
|
||||
self._test_obtain_certificate_common(key, csr)
|
||||
|
||||
mock_crypto.make_key.assert_called_once_with(self.config.rsa_key_size)
|
||||
mock_acme_crypto.make_csr.assert_called_once_with(
|
||||
|
|
@ -322,14 +312,14 @@ class ClientTest(ClientTestCommon):
|
|||
@mock.patch("certbot.cli.helpful_parser")
|
||||
def test_save_certificate(self, mock_parser):
|
||||
# pylint: disable=too-many-locals
|
||||
certs = ["matching_cert.pem", "cert.pem", "cert-san.pem"]
|
||||
certs = ["cert_512.pem", "cert-san_512.pem"]
|
||||
tmp_path = tempfile.mkdtemp()
|
||||
os.chmod(tmp_path, 0o755) # TODO: really??
|
||||
|
||||
certr = mock.MagicMock(body=test_util.load_comparable_cert(certs[0]))
|
||||
chain_cert = [test_util.load_comparable_cert(certs[1]),
|
||||
test_util.load_comparable_cert(certs[2])]
|
||||
candidate_cert_path = os.path.join(tmp_path, "certs", "cert.pem")
|
||||
chain_cert = [test_util.load_comparable_cert(certs[0]),
|
||||
test_util.load_comparable_cert(certs[1])]
|
||||
candidate_cert_path = os.path.join(tmp_path, "certs", "cert_512.pem")
|
||||
candidate_chain_path = os.path.join(tmp_path, "chains", "chain.pem")
|
||||
candidate_fullchain_path = os.path.join(tmp_path, "chains", "fullchain.pem")
|
||||
mock_parser.verb = "certonly"
|
||||
|
|
@ -354,8 +344,8 @@ class ClientTest(ClientTestCommon):
|
|||
|
||||
with open(chain_path, "rb") as chain_file:
|
||||
chain_contents = chain_file.read()
|
||||
self.assertEqual(chain_contents, test_util.load_vector(certs[1]) +
|
||||
test_util.load_vector(certs[2]))
|
||||
self.assertEqual(chain_contents, test_util.load_vector(certs[0]) +
|
||||
test_util.load_vector(certs[1]))
|
||||
|
||||
shutil.rmtree(tmp_path)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,33 +6,32 @@ import mock
|
|||
|
||||
from certbot import errors
|
||||
|
||||
from certbot.tests import util as test_util
|
||||
|
||||
class NamespaceConfigTest(unittest.TestCase):
|
||||
class NamespaceConfigTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.configuration.NamespaceConfig."""
|
||||
|
||||
def setUp(self):
|
||||
self.namespace = mock.MagicMock(
|
||||
config_dir='/tmp/config', work_dir='/tmp/foo',
|
||||
logs_dir="/tmp/bar", foo='bar',
|
||||
server='https://acme-server.org:443/new',
|
||||
tls_sni_01_port=1234, http01_port=4321)
|
||||
from certbot.configuration import NamespaceConfig
|
||||
self.config = NamespaceConfig(self.namespace)
|
||||
super(NamespaceConfigTest, self).setUp()
|
||||
self.config.foo = 'bar'
|
||||
self.config.server = 'https://acme-server.org:443/new'
|
||||
self.config.tls_sni_01_port = 1234
|
||||
self.config.http01_port = 4321
|
||||
|
||||
def test_init_same_ports(self):
|
||||
self.namespace.tls_sni_01_port = 4321
|
||||
self.config.namespace.tls_sni_01_port = 4321
|
||||
from certbot.configuration import NamespaceConfig
|
||||
self.assertRaises(errors.Error, NamespaceConfig, self.namespace)
|
||||
self.assertRaises(errors.Error, NamespaceConfig, self.config.namespace)
|
||||
|
||||
def test_proxy_getattr(self):
|
||||
self.assertEqual(self.config.foo, 'bar')
|
||||
self.assertEqual(self.config.work_dir, '/tmp/foo')
|
||||
self.assertEqual(self.config.work_dir, os.path.join(self.tempdir, 'work'))
|
||||
|
||||
def test_server_path(self):
|
||||
self.assertEqual(['acme-server.org:443', 'new'],
|
||||
self.config.server_path.split(os.path.sep))
|
||||
|
||||
self.namespace.server = ('http://user:pass@acme.server:443'
|
||||
self.config.namespace.server = ('http://user:pass@acme.server:443'
|
||||
'/p/a/t/h;parameters?query#fragment')
|
||||
self.assertEqual(['user:pass@acme.server:443', 'p', 'a', 't', 'h'],
|
||||
self.config.server_path.split(os.path.sep))
|
||||
|
|
@ -48,12 +47,18 @@ class NamespaceConfigTest(unittest.TestCase):
|
|||
constants.TEMP_CHECKPOINT_DIR = 't'
|
||||
|
||||
self.assertEqual(
|
||||
self.config.accounts_dir, '/tmp/config/acc/acme-server.org:443/new')
|
||||
self.assertEqual(self.config.backup_dir, '/tmp/foo/backups')
|
||||
self.assertEqual(self.config.csr_dir, '/tmp/config/csr')
|
||||
self.assertEqual(self.config.in_progress_dir, '/tmp/foo/../p')
|
||||
self.assertEqual(self.config.key_dir, '/tmp/config/keys')
|
||||
self.assertEqual(self.config.temp_checkpoint_dir, '/tmp/foo/t')
|
||||
self.config.accounts_dir, os.path.join(
|
||||
self.config.config_dir, 'acc/acme-server.org:443/new'))
|
||||
self.assertEqual(
|
||||
self.config.backup_dir, os.path.join(self.config.work_dir, 'backups'))
|
||||
self.assertEqual(
|
||||
self.config.csr_dir, os.path.join(self.config.config_dir, 'csr'))
|
||||
self.assertEqual(
|
||||
self.config.in_progress_dir, os.path.join(self.config.work_dir, '../p'))
|
||||
self.assertEqual(
|
||||
self.config.key_dir, os.path.join(self.config.config_dir, 'keys'))
|
||||
self.assertEqual(
|
||||
self.config.temp_checkpoint_dir, os.path.join(self.config.work_dir, 't'))
|
||||
|
||||
def test_absolute_paths(self):
|
||||
from certbot.configuration import NamespaceConfig
|
||||
|
|
@ -95,10 +100,13 @@ class NamespaceConfigTest(unittest.TestCase):
|
|||
constants.LIVE_DIR = 'l'
|
||||
constants.RENEWAL_CONFIGS_DIR = 'renewal_configs'
|
||||
|
||||
self.assertEqual(self.config.default_archive_dir, '/tmp/config/a')
|
||||
self.assertEqual(self.config.live_dir, '/tmp/config/l')
|
||||
self.assertEqual(
|
||||
self.config.renewal_configs_dir, '/tmp/config/renewal_configs')
|
||||
self.config.default_archive_dir, os.path.join(self.config.config_dir, 'a'))
|
||||
self.assertEqual(
|
||||
self.config.live_dir, os.path.join(self.config.config_dir, 'l'))
|
||||
self.assertEqual(
|
||||
self.config.renewal_configs_dir, os.path.join(
|
||||
self.config.config_dir, 'renewal_configs'))
|
||||
|
||||
def test_renewal_absolute_paths(self):
|
||||
from certbot.configuration import NamespaceConfig
|
||||
|
|
|
|||
|
|
@ -17,11 +17,10 @@ RSA256_KEY = test_util.load_vector('rsa256_key.pem')
|
|||
RSA256_KEY_PATH = test_util.vector_path('rsa256_key.pem')
|
||||
RSA512_KEY = test_util.load_vector('rsa512_key.pem')
|
||||
RSA2048_KEY_PATH = test_util.vector_path('rsa2048_key.pem')
|
||||
CERT_PATH = test_util.vector_path('cert.pem')
|
||||
CERT = test_util.load_vector('cert.pem')
|
||||
SAN_CERT = test_util.load_vector('cert-san.pem')
|
||||
SS_CERT_PATH = test_util.vector_path('self_signed_cert.pem')
|
||||
SS_CERT = test_util.load_vector('self_signed_cert.pem')
|
||||
CERT_PATH = test_util.vector_path('cert_512.pem')
|
||||
CERT = test_util.load_vector('cert_512.pem')
|
||||
SS_CERT_PATH = test_util.vector_path('cert_2048.pem')
|
||||
SS_CERT = test_util.load_vector('cert_2048.pem')
|
||||
|
||||
class InitSaveKeyTest(test_util.TempDirTestCase):
|
||||
"""Tests for certbot.crypto_util.init_save_key."""
|
||||
|
|
@ -88,13 +87,13 @@ class ValidCSRTest(unittest.TestCase):
|
|||
return valid_csr(csr)
|
||||
|
||||
def test_valid_pem_true(self):
|
||||
self.assertTrue(self._call(test_util.load_vector('csr.pem')))
|
||||
self.assertTrue(self._call(test_util.load_vector('csr_512.pem')))
|
||||
|
||||
def test_valid_pem_san_true(self):
|
||||
self.assertTrue(self._call(test_util.load_vector('csr-san.pem')))
|
||||
self.assertTrue(self._call(test_util.load_vector('csr-san_512.pem')))
|
||||
|
||||
def test_valid_der_false(self):
|
||||
self.assertFalse(self._call(test_util.load_vector('csr.der')))
|
||||
self.assertFalse(self._call(test_util.load_vector('csr_512.der')))
|
||||
|
||||
def test_empty_false(self):
|
||||
self.assertFalse(self._call(''))
|
||||
|
|
@ -113,11 +112,11 @@ class CSRMatchesPubkeyTest(unittest.TestCase):
|
|||
|
||||
def test_valid_true(self):
|
||||
self.assertTrue(self._call(
|
||||
test_util.load_vector('csr.pem'), RSA512_KEY))
|
||||
test_util.load_vector('csr_512.pem'), RSA512_KEY))
|
||||
|
||||
def test_invalid_false(self):
|
||||
self.assertFalse(self._call(
|
||||
test_util.load_vector('csr.pem'), RSA256_KEY))
|
||||
test_util.load_vector('csr_512.pem'), RSA256_KEY))
|
||||
|
||||
|
||||
class ImportCSRFileTest(unittest.TestCase):
|
||||
|
|
@ -129,9 +128,9 @@ class ImportCSRFileTest(unittest.TestCase):
|
|||
return import_csr_file(*args, **kwargs)
|
||||
|
||||
def test_der_csr(self):
|
||||
csrfile = test_util.vector_path('csr.der')
|
||||
data = test_util.load_vector('csr.der')
|
||||
data_pem = test_util.load_vector('csr.pem')
|
||||
csrfile = test_util.vector_path('csr_512.der')
|
||||
data = test_util.load_vector('csr_512.der')
|
||||
data_pem = test_util.load_vector('csr_512.pem')
|
||||
|
||||
self.assertEqual(
|
||||
(OpenSSL.crypto.FILETYPE_PEM,
|
||||
|
|
@ -142,8 +141,8 @@ class ImportCSRFileTest(unittest.TestCase):
|
|||
self._call(csrfile, data))
|
||||
|
||||
def test_pem_csr(self):
|
||||
csrfile = test_util.vector_path('csr.pem')
|
||||
data = test_util.load_vector('csr.pem')
|
||||
csrfile = test_util.vector_path('csr_512.pem')
|
||||
data = test_util.load_vector('csr_512.pem')
|
||||
|
||||
self.assertEqual(
|
||||
(OpenSSL.crypto.FILETYPE_PEM,
|
||||
|
|
@ -155,8 +154,8 @@ class ImportCSRFileTest(unittest.TestCase):
|
|||
|
||||
def test_bad_csr(self):
|
||||
self.assertRaises(errors.Error, self._call,
|
||||
test_util.vector_path('cert.pem'),
|
||||
test_util.load_vector('cert.pem'))
|
||||
test_util.vector_path('cert_512.pem'),
|
||||
test_util.load_vector('cert_512.pem'))
|
||||
|
||||
|
||||
class MakeKeyTest(unittest.TestCase): # pylint: disable=too-few-public-methods
|
||||
|
|
@ -179,7 +178,7 @@ class VerifyCertSetup(unittest.TestCase):
|
|||
self.renewable_cert.cert = SS_CERT_PATH
|
||||
self.renewable_cert.chain = SS_CERT_PATH
|
||||
self.renewable_cert.privkey = RSA2048_KEY_PATH
|
||||
self.renewable_cert.fullchain = test_util.vector_path('self_signed_fullchain.pem')
|
||||
self.renewable_cert.fullchain = test_util.vector_path('cert_fullchain_2048.pem')
|
||||
|
||||
self.bad_renewable_cert = mock.MagicMock()
|
||||
self.bad_renewable_cert.chain = SS_CERT_PATH
|
||||
|
|
@ -219,7 +218,7 @@ class VerifyRenewableCertSigTest(VerifyCertSetup):
|
|||
self.assertEqual(None, self._call(self.renewable_cert))
|
||||
|
||||
def test_cert_sig_mismatch(self):
|
||||
self.bad_renewable_cert.cert = test_util.vector_path('self_signed_cert_bad.pem')
|
||||
self.bad_renewable_cert.cert = test_util.vector_path('cert_512_bad.pem')
|
||||
self.assertRaises(errors.Error, self._call, self.bad_renewable_cert)
|
||||
|
||||
|
||||
|
|
@ -275,7 +274,7 @@ class ValidPrivkeyTest(unittest.TestCase):
|
|||
return valid_privkey(privkey)
|
||||
|
||||
def test_valid_true(self):
|
||||
self.assertTrue(self._call(RSA256_KEY))
|
||||
self.assertTrue(self._call(RSA512_KEY))
|
||||
|
||||
def test_empty_false(self):
|
||||
self.assertFalse(self._call(''))
|
||||
|
|
@ -293,12 +292,12 @@ class GetSANsFromCertTest(unittest.TestCase):
|
|||
return get_sans_from_cert(*args, **kwargs)
|
||||
|
||||
def test_single(self):
|
||||
self.assertEqual([], self._call(test_util.load_vector('cert.pem')))
|
||||
self.assertEqual([], self._call(test_util.load_vector('cert_512.pem')))
|
||||
|
||||
def test_san(self):
|
||||
self.assertEqual(
|
||||
['example.com', 'www.example.com'],
|
||||
self._call(test_util.load_vector('cert-san.pem')))
|
||||
self._call(test_util.load_vector('cert-san_512.pem')))
|
||||
|
||||
|
||||
class GetNamesFromCertTest(unittest.TestCase):
|
||||
|
|
@ -312,19 +311,19 @@ class GetNamesFromCertTest(unittest.TestCase):
|
|||
def test_single(self):
|
||||
self.assertEqual(
|
||||
['example.com'],
|
||||
self._call(test_util.load_vector('cert.pem')))
|
||||
self._call(test_util.load_vector('cert_512.pem')))
|
||||
|
||||
def test_san(self):
|
||||
self.assertEqual(
|
||||
['example.com', 'www.example.com'],
|
||||
self._call(test_util.load_vector('cert-san.pem')))
|
||||
self._call(test_util.load_vector('cert-san_512.pem')))
|
||||
|
||||
def test_common_name_sans_order(self):
|
||||
# Tests that the common name comes first
|
||||
# followed by the SANS in alphabetical order
|
||||
self.assertEqual(
|
||||
['example.com'] + ['{0}.example.com'.format(c) for c in 'abcd'],
|
||||
self._call(test_util.load_vector('cert-5sans.pem')))
|
||||
self._call(test_util.load_vector('cert-5sans_512.pem')))
|
||||
|
||||
def test_parse_non_cert(self):
|
||||
self.assertRaises(OpenSSL.crypto.Error, self._call, "hello there")
|
||||
|
|
|
|||
|
|
@ -4,20 +4,22 @@ import unittest
|
|||
import mock
|
||||
|
||||
from certbot import constants
|
||||
from certbot.tests import util
|
||||
import certbot.tests.util as test_util
|
||||
|
||||
|
||||
class HandleSubscriptionTest(unittest.TestCase):
|
||||
class HandleSubscriptionTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.eff.handle_subscription."""
|
||||
def setUp(self):
|
||||
super(HandleSubscriptionTest, self).setUp()
|
||||
self.email = 'certbot@example.org'
|
||||
self.config = mock.Mock(email=self.email, eff_email=None)
|
||||
self.config.email = self.email
|
||||
self.config.eff_email = None
|
||||
|
||||
def _call(self):
|
||||
from certbot.eff import handle_subscription
|
||||
return handle_subscription(self.config)
|
||||
|
||||
@util.patch_get_utility()
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch('certbot.eff.subscribe')
|
||||
def test_failure(self, mock_subscribe, mock_get_utility):
|
||||
self.config.email = None
|
||||
|
|
@ -32,12 +34,12 @@ class HandleSubscriptionTest(unittest.TestCase):
|
|||
@mock.patch('certbot.eff.subscribe')
|
||||
def test_no_subscribe_with_no_prompt(self, mock_subscribe):
|
||||
self.config.eff_email = False
|
||||
with util.patch_get_utility() as mock_get_utility:
|
||||
with test_util.patch_get_utility() as mock_get_utility:
|
||||
self._call()
|
||||
self.assertFalse(mock_subscribe.called)
|
||||
self._assert_no_get_utility_calls(mock_get_utility)
|
||||
|
||||
@util.patch_get_utility()
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch('certbot.eff.subscribe')
|
||||
def test_subscribe_with_no_prompt(self, mock_subscribe, mock_get_utility):
|
||||
self.config.eff_email = True
|
||||
|
|
@ -49,7 +51,7 @@ class HandleSubscriptionTest(unittest.TestCase):
|
|||
self.assertFalse(mock_get_utility().yesno.called)
|
||||
self.assertFalse(mock_get_utility().add_message.called)
|
||||
|
||||
@util.patch_get_utility()
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch('certbot.eff.subscribe')
|
||||
def test_subscribe_with_prompt(self, mock_subscribe, mock_get_utility):
|
||||
mock_get_utility().yesno.return_value = True
|
||||
|
|
@ -62,7 +64,7 @@ class HandleSubscriptionTest(unittest.TestCase):
|
|||
self.assertTrue(mock_subscribe.called)
|
||||
self.assertEqual(mock_subscribe.call_args[0][0], self.email)
|
||||
|
||||
@util.patch_get_utility()
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch('certbot.eff.subscribe')
|
||||
def test_no_subscribe_with_prompt(self, mock_subscribe, mock_get_utility):
|
||||
mock_get_utility().yesno.return_value = False
|
||||
|
|
@ -105,7 +107,7 @@ class SubscribeTest(unittest.TestCase):
|
|||
self.assertFalse(data is None)
|
||||
self.assertEqual(data.get('email'), self.email)
|
||||
|
||||
@util.patch_get_utility()
|
||||
@test_util.patch_get_utility()
|
||||
def test_bad_status(self, mock_get_utility):
|
||||
self.json['status'] = False
|
||||
self._call() # pylint: disable=no-value-for-parameter
|
||||
|
|
@ -113,7 +115,7 @@ class SubscribeTest(unittest.TestCase):
|
|||
expected_part = 'because your e-mail address appears to be invalid.'
|
||||
self.assertTrue(expected_part in actual)
|
||||
|
||||
@util.patch_get_utility()
|
||||
@test_util.patch_get_utility()
|
||||
def test_not_ok(self, mock_get_utility):
|
||||
self.response.ok = False
|
||||
self._call() # pylint: disable=no-value-for-parameter
|
||||
|
|
@ -125,7 +127,7 @@ class SubscribeTest(unittest.TestCase):
|
|||
self.assertTrue(mock_get_utility().add_message.called)
|
||||
return mock_get_utility().add_message.call_args[0][0]
|
||||
|
||||
@util.patch_get_utility()
|
||||
@test_util.patch_get_utility()
|
||||
def test_subscribe(self, mock_get_utility):
|
||||
self._call() # pylint: disable=no-value-for-parameter
|
||||
self.assertFalse(mock_get_utility.called)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class PreArgParseSetupTest(unittest.TestCase):
|
|||
memory_handler, 1, 2, 3, debug=True, log_path=mock.ANY)
|
||||
|
||||
|
||||
class PostArgParseSetupTest(test_util.TempDirTestCase):
|
||||
class PostArgParseSetupTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.log.post_arg_parse_setup."""
|
||||
|
||||
@classmethod
|
||||
|
|
@ -65,9 +65,10 @@ class PostArgParseSetupTest(test_util.TempDirTestCase):
|
|||
|
||||
def setUp(self):
|
||||
super(PostArgParseSetupTest, self).setUp()
|
||||
self.config = mock.MagicMock(
|
||||
debug=False, logs_dir=self.tempdir, max_log_backups=1000,
|
||||
quiet=False, verbose_count=constants.CLI_DEFAULTS['verbose_count'])
|
||||
self.config.debug = False
|
||||
self.config.max_log_backups = 1000
|
||||
self.config.quiet = False
|
||||
self.config.verbose_count = constants.CLI_DEFAULTS['verbose_count']
|
||||
self.devnull = open(os.devnull, 'w')
|
||||
|
||||
from certbot.log import ColoredStreamHandler
|
||||
|
|
@ -102,7 +103,7 @@ class PostArgParseSetupTest(test_util.TempDirTestCase):
|
|||
self.assertFalse(os.path.exists(self.temp_path))
|
||||
mock_sys.excepthook(1, 2, 3)
|
||||
mock_except_hook.assert_called_once_with(
|
||||
1, 2, 3, debug=self.config.debug, log_path=self.tempdir)
|
||||
1, 2, 3, debug=self.config.debug, log_path=self.config.logs_dir)
|
||||
|
||||
level = self.stream_handler.level
|
||||
if self.config.quiet:
|
||||
|
|
@ -119,7 +120,7 @@ class PostArgParseSetupTest(test_util.TempDirTestCase):
|
|||
self.test_common()
|
||||
|
||||
|
||||
class SetupLogFileHandlerTest(test_util.TempDirTestCase):
|
||||
class SetupLogFileHandlerTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.log.setup_log_file_handler."""
|
||||
|
||||
@classmethod
|
||||
|
|
@ -129,7 +130,7 @@ class SetupLogFileHandlerTest(test_util.TempDirTestCase):
|
|||
|
||||
def setUp(self):
|
||||
super(SetupLogFileHandlerTest, self).setUp()
|
||||
self.config = mock.MagicMock(logs_dir=self.tempdir, max_log_backups=42)
|
||||
self.config.max_log_backups = 42
|
||||
|
||||
@mock.patch('certbot.main.logging.handlers.RotatingFileHandler')
|
||||
def test_failure(self, mock_handler):
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ from certbot import configuration
|
|||
from certbot import crypto_util
|
||||
from certbot import errors
|
||||
from certbot import main
|
||||
from certbot import renewal
|
||||
from certbot import storage
|
||||
from certbot import util
|
||||
|
||||
from certbot.plugins import disco
|
||||
|
|
@ -32,13 +30,13 @@ from certbot.plugins import manual
|
|||
|
||||
import certbot.tests.util as test_util
|
||||
|
||||
CERT_PATH = test_util.vector_path('cert.pem')
|
||||
CERT = test_util.vector_path('cert.pem')
|
||||
CSR = test_util.vector_path('csr.der')
|
||||
CERT_PATH = test_util.vector_path('cert_512.pem')
|
||||
CERT = test_util.vector_path('cert_512.pem')
|
||||
CSR = test_util.vector_path('csr_512.der')
|
||||
KEY = test_util.vector_path('rsa256_key.pem')
|
||||
JWK = jose.JWKRSA.load(test_util.load_vector("rsa512_key_2.pem"))
|
||||
JWK = jose.JWKRSA.load(test_util.load_vector('rsa512_key.pem'))
|
||||
RSA2048_KEY_PATH = test_util.vector_path('rsa2048_key.pem')
|
||||
SS_CERT_PATH = test_util.vector_path('self_signed_cert.pem')
|
||||
SS_CERT_PATH = test_util.vector_path('cert_2048.pem')
|
||||
|
||||
|
||||
class TestHandleIdenticalCerts(unittest.TestCase):
|
||||
|
|
@ -227,7 +225,7 @@ class RevokeTest(test_util.TempDirTestCase):
|
|||
|
||||
shutil.copy(CERT_PATH, self.tempdir)
|
||||
self.tmp_cert_path = os.path.abspath(os.path.join(self.tempdir,
|
||||
'cert.pem'))
|
||||
'cert_512.pem'))
|
||||
|
||||
self.patches = [
|
||||
mock.patch('acme.client.Client', autospec=True),
|
||||
|
|
@ -289,16 +287,14 @@ class RevokeTest(test_util.TempDirTestCase):
|
|||
self.mock_success_revoke.assert_not_called()
|
||||
|
||||
|
||||
class DetermineAccountTest(unittest.TestCase):
|
||||
class DetermineAccountTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.main._determine_account."""
|
||||
|
||||
def setUp(self):
|
||||
self.args = mock.MagicMock(account=None, email=None,
|
||||
config_dir="unused_config",
|
||||
logs_dir="unused_logs",
|
||||
work_dir="unused_work",
|
||||
register_unsafely_without_email=False)
|
||||
self.config = configuration.NamespaceConfig(self.args)
|
||||
super(DetermineAccountTest, self).setUp()
|
||||
self.config.account = None
|
||||
self.config.email = None
|
||||
self.config.register_unsafely_without_email = False
|
||||
self.accs = [mock.MagicMock(id='x'), mock.MagicMock(id='y')]
|
||||
self.account_storage = account.AccountMemoryStorage()
|
||||
# For use in saving accounts: fake out the new_authz URL.
|
||||
|
|
@ -359,19 +355,16 @@ class DetermineAccountTest(unittest.TestCase):
|
|||
self.assertEqual('other email', self.config.email)
|
||||
|
||||
|
||||
class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-methods
|
||||
class MainTest(test_util.ConfigTestCase): # pylint: disable=too-many-public-methods
|
||||
"""Tests for different commands."""
|
||||
|
||||
def setUp(self):
|
||||
super(MainTest, self).setUp()
|
||||
|
||||
self.config_dir = os.path.join(self.tempdir, 'config')
|
||||
self.work_dir = os.path.join(self.tempdir, 'work')
|
||||
self.logs_dir = os.path.join(self.tempdir, 'logs')
|
||||
os.mkdir(self.logs_dir)
|
||||
self.standard_args = ['--config-dir', self.config_dir,
|
||||
'--work-dir', self.work_dir,
|
||||
'--logs-dir', self.logs_dir, '--text']
|
||||
os.mkdir(self.config.logs_dir)
|
||||
self.standard_args = ['--config-dir', self.config.config_dir,
|
||||
'--work-dir', self.config.work_dir,
|
||||
'--logs-dir', self.config.logs_dir, '--text']
|
||||
|
||||
def tearDown(self):
|
||||
# Reset globals in cli
|
||||
|
|
@ -647,7 +640,7 @@ class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-me
|
|||
self.assertRaises(
|
||||
errors.Error, self._call,
|
||||
'certonly --csr {0}'.format(
|
||||
test_util.vector_path('csr-nonames.pem')).split())
|
||||
test_util.vector_path('csr-nonames_512.pem')).split())
|
||||
|
||||
def test_csr_with_inconsistent_domains(self):
|
||||
self.assertRaises(
|
||||
|
|
@ -707,7 +700,7 @@ class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-me
|
|||
def _test_renewal_common(self, due_for_renewal, extra_args, log_out=None,
|
||||
args=None, should_renew=True, error_expected=False):
|
||||
# pylint: disable=too-many-locals,too-many-arguments
|
||||
cert_path = test_util.vector_path('cert.pem')
|
||||
cert_path = test_util.vector_path('cert_512.pem')
|
||||
chain_path = '/etc/letsencrypt/live/foo.bar/fullchain.pem'
|
||||
mock_lineage = mock.MagicMock(cert=cert_path, fullchain=chain_path,
|
||||
cert_path=cert_path, fullchain_path=chain_path)
|
||||
|
|
@ -756,7 +749,7 @@ class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-me
|
|||
raise
|
||||
finally:
|
||||
if log_out:
|
||||
with open(os.path.join(self.logs_dir, "letsencrypt.log")) as lf:
|
||||
with open(os.path.join(self.config.logs_dir, "letsencrypt.log")) as lf:
|
||||
self.assertTrue(log_out in lf.read())
|
||||
|
||||
return mock_lineage, mock_get_utility, stdout
|
||||
|
|
@ -788,18 +781,18 @@ class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-me
|
|||
|
||||
def _dump_log(self):
|
||||
print("Logs:")
|
||||
log_path = os.path.join(self.logs_dir, "letsencrypt.log")
|
||||
log_path = os.path.join(self.config.logs_dir, "letsencrypt.log")
|
||||
if os.path.exists(log_path):
|
||||
with open(log_path) as lf:
|
||||
print(lf.read())
|
||||
|
||||
def test_renew_verb(self):
|
||||
test_util.make_lineage(self.config_dir, 'sample-renewal.conf')
|
||||
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf')
|
||||
args = ["renew", "--dry-run", "-tvv"]
|
||||
self._test_renewal_common(True, [], args=args, should_renew=True)
|
||||
|
||||
def test_quiet_renew(self):
|
||||
test_util.make_lineage(self.config_dir, 'sample-renewal.conf')
|
||||
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf')
|
||||
args = ["renew", "--dry-run"]
|
||||
_, _, stdout = self._test_renewal_common(True, [], args=args, should_renew=True)
|
||||
out = stdout.getvalue()
|
||||
|
|
@ -811,36 +804,21 @@ class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-me
|
|||
self.assertEqual("", out)
|
||||
|
||||
def test_renew_hook_validation(self):
|
||||
test_util.make_lineage(self.config_dir, 'sample-renewal.conf')
|
||||
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf')
|
||||
args = ["renew", "--dry-run", "--post-hook=no-such-command"]
|
||||
self._test_renewal_common(True, [], args=args, should_renew=False,
|
||||
error_expected=True)
|
||||
|
||||
def test_renew_no_hook_validation(self):
|
||||
test_util.make_lineage(self.config_dir, 'sample-renewal.conf')
|
||||
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf')
|
||||
args = ["renew", "--dry-run", "--post-hook=no-such-command",
|
||||
"--disable-hook-validation"]
|
||||
with mock.patch("certbot.hooks.post_hook"):
|
||||
self._test_renewal_common(True, [], args=args, should_renew=True,
|
||||
error_expected=False)
|
||||
|
||||
@mock.patch("certbot.cli.set_by_cli")
|
||||
def test_ancient_webroot_renewal_conf(self, mock_set_by_cli):
|
||||
mock_set_by_cli.return_value = False
|
||||
rc_path = test_util.make_lineage(
|
||||
self.config_dir, 'sample-renewal-ancient.conf')
|
||||
args = mock.MagicMock(account=None, config_dir=self.config_dir,
|
||||
logs_dir=self.logs_dir, work_dir=self.work_dir,
|
||||
email=None, webroot_path=None)
|
||||
config = configuration.NamespaceConfig(args)
|
||||
lineage = storage.RenewableCert(rc_path, config)
|
||||
renewalparams = lineage.configuration["renewalparams"]
|
||||
# pylint: disable=protected-access
|
||||
renewal._restore_webroot_config(config, renewalparams)
|
||||
self.assertEqual(config.webroot_path, ["/var/www/"])
|
||||
|
||||
def test_renew_verb_empty_config(self):
|
||||
rd = os.path.join(self.config_dir, 'renewal')
|
||||
rd = os.path.join(self.config.config_dir, 'renewal')
|
||||
if not os.path.exists(rd):
|
||||
os.makedirs(rd)
|
||||
with open(os.path.join(rd, 'empty.conf'), 'w'):
|
||||
|
|
@ -849,7 +827,7 @@ class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-me
|
|||
self._test_renewal_common(False, [], args=args, should_renew=False, error_expected=True)
|
||||
|
||||
def test_renew_with_certname(self):
|
||||
test_util.make_lineage(self.config_dir, 'sample-renewal.conf')
|
||||
test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf')
|
||||
self._test_renewal_common(True, [], should_renew=True,
|
||||
args=['renew', '--dry-run', '--cert-name', 'sample-renewal'])
|
||||
|
||||
|
|
@ -859,7 +837,7 @@ class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-me
|
|||
error_expected=True)
|
||||
|
||||
def _make_dummy_renewal_config(self):
|
||||
renewer_configs_dir = os.path.join(self.config_dir, 'renewal')
|
||||
renewer_configs_dir = os.path.join(self.config.config_dir, 'renewal')
|
||||
os.makedirs(renewer_configs_dir)
|
||||
with open(os.path.join(renewer_configs_dir, 'test.conf'), 'w') as f:
|
||||
f.write("My contents don't matter")
|
||||
|
|
@ -977,7 +955,7 @@ class MainTest(test_util.TempDirTestCase): # pylint: disable=too-many-public-me
|
|||
chain = 'chain'
|
||||
mock_client = mock.MagicMock()
|
||||
mock_client.obtain_certificate_from_csr.return_value = (certr, chain)
|
||||
cert_path = '/etc/letsencrypt/live/example.com/cert.pem'
|
||||
cert_path = '/etc/letsencrypt/live/example.com/cert_512.pem'
|
||||
full_path = '/etc/letsencrypt/live/example.com/fullchain.pem'
|
||||
mock_client.save_certificate.return_value = cert_path, None, full_path
|
||||
with mock.patch('certbot.main._init_le_client') as mock_init:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
"""Tests for certbot.renewal"""
|
||||
import os
|
||||
import mock
|
||||
import unittest
|
||||
|
||||
|
|
@ -9,24 +8,22 @@ from certbot import configuration
|
|||
from certbot import errors
|
||||
from certbot import storage
|
||||
|
||||
from certbot.tests import util
|
||||
import certbot.tests.util as test_util
|
||||
|
||||
|
||||
class RenewalTest(util.TempDirTestCase):
|
||||
class RenewalTest(test_util.ConfigTestCase):
|
||||
def setUp(self):
|
||||
super(RenewalTest, self).setUp()
|
||||
|
||||
self.config_dir = os.path.join(self.tempdir, 'config')
|
||||
|
||||
@mock.patch('certbot.cli.set_by_cli')
|
||||
def test_ancient_webroot_renewal_conf(self, mock_set_by_cli):
|
||||
mock_set_by_cli.return_value = False
|
||||
rc_path = util.make_lineage(
|
||||
self.config_dir, 'sample-renewal-ancient.conf')
|
||||
args = mock.MagicMock(account=None, config_dir=self.config_dir,
|
||||
logs_dir="logs", work_dir="work",
|
||||
email=None, webroot_path=None)
|
||||
config = configuration.NamespaceConfig(args)
|
||||
rc_path = test_util.make_lineage(
|
||||
self.config.config_dir, 'sample-renewal-ancient.conf')
|
||||
self.config.account = None
|
||||
self.config.email = None
|
||||
self.config.webroot_path = None
|
||||
config = configuration.NamespaceConfig(self.config)
|
||||
lineage = storage.RenewableCert(rc_path, config)
|
||||
renewalparams = lineage.configuration['renewalparams']
|
||||
# pylint: disable=protected-access
|
||||
|
|
@ -35,10 +32,10 @@ class RenewalTest(util.TempDirTestCase):
|
|||
self.assertEqual(config.webroot_path, ['/var/www/'])
|
||||
|
||||
|
||||
class RestoreRequiredConfigElementsTest(unittest.TestCase):
|
||||
class RestoreRequiredConfigElementsTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot.renewal.restore_required_config_elements."""
|
||||
def setUp(self):
|
||||
self.config = mock.MagicMock()
|
||||
super(RestoreRequiredConfigElementsTest, self).setUp()
|
||||
|
||||
@classmethod
|
||||
def _call(cls, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -14,16 +14,16 @@ from certbot import errors
|
|||
from certbot.tests import util as test_util
|
||||
|
||||
|
||||
class ReverterCheckpointLocalTest(unittest.TestCase):
|
||||
class ReverterCheckpointLocalTest(test_util.ConfigTestCase):
|
||||
# pylint: disable=too-many-instance-attributes, too-many-public-methods
|
||||
"""Test the Reverter Class."""
|
||||
def setUp(self):
|
||||
super(ReverterCheckpointLocalTest, self).setUp()
|
||||
from certbot.reverter import Reverter
|
||||
|
||||
# Disable spurious errors... we are trying to test for them
|
||||
logging.disable(logging.CRITICAL)
|
||||
|
||||
self.config = setup_work_direc()
|
||||
self.reverter = Reverter(self.config)
|
||||
|
||||
tup = setup_test_files()
|
||||
|
|
@ -277,15 +277,15 @@ class ReverterCheckpointLocalTest(unittest.TestCase):
|
|||
self.assertEqual(read_in(self.config2), "directive-dir2")
|
||||
|
||||
|
||||
class TestFullCheckpointsReverter(unittest.TestCase):
|
||||
class TestFullCheckpointsReverter(test_util.ConfigTestCase):
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
"""Tests functions having to deal with full checkpoints."""
|
||||
def setUp(self):
|
||||
super(TestFullCheckpointsReverter, self).setUp()
|
||||
from certbot.reverter import Reverter
|
||||
# Disable spurious errors...
|
||||
logging.disable(logging.CRITICAL)
|
||||
|
||||
self.config = setup_work_direc()
|
||||
self.reverter = Reverter(self.config)
|
||||
|
||||
tup = setup_test_files()
|
||||
|
|
@ -439,21 +439,6 @@ class TestFullCheckpointsReverter(unittest.TestCase):
|
|||
return config3
|
||||
|
||||
|
||||
def setup_work_direc():
|
||||
"""Setup directories.
|
||||
|
||||
:returns: Mocked :class:`certbot.interfaces.IConfig`
|
||||
|
||||
"""
|
||||
work_dir = tempfile.mkdtemp("work")
|
||||
backup_dir = os.path.join(work_dir, "backup")
|
||||
|
||||
return mock.MagicMock(
|
||||
work_dir=work_dir, backup_dir=backup_dir,
|
||||
temp_checkpoint_dir=os.path.join(work_dir, "temp"),
|
||||
in_progress_dir=os.path.join(backup_dir, "in_progress_dir"))
|
||||
|
||||
|
||||
def setup_test_files():
|
||||
"""Setup sample configuration files."""
|
||||
dir1 = tempfile.mkdtemp("dir1")
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@ import six
|
|||
|
||||
import certbot
|
||||
from certbot import cli
|
||||
from certbot import configuration
|
||||
from certbot import errors
|
||||
from certbot.storage import ALL_FOUR
|
||||
|
||||
from certbot.tests import util
|
||||
import certbot.tests.util as test_util
|
||||
|
||||
|
||||
CERT = util.load_cert('cert.pem')
|
||||
CERT = test_util.load_cert('cert_512.pem')
|
||||
|
||||
|
||||
|
||||
def unlink_all(rc_object):
|
||||
|
|
@ -36,7 +36,7 @@ def fill_with_sample_data(rc_object):
|
|||
f.write(kind)
|
||||
|
||||
|
||||
class BaseRenewableCertTest(util.TempDirTestCase):
|
||||
class BaseRenewableCertTest(test_util.ConfigTestCase):
|
||||
"""Base class for setting up Renewable Cert tests.
|
||||
|
||||
.. note:: It may be required to write out self.config for
|
||||
|
|
@ -50,39 +50,31 @@ class BaseRenewableCertTest(util.TempDirTestCase):
|
|||
|
||||
super(BaseRenewableCertTest, self).setUp()
|
||||
|
||||
self.cli_config = configuration.NamespaceConfig(
|
||||
namespace=mock.MagicMock(
|
||||
config_dir=self.tempdir,
|
||||
work_dir=self.tempdir,
|
||||
logs_dir=self.tempdir,
|
||||
)
|
||||
)
|
||||
|
||||
# TODO: maybe provide NamespaceConfig.make_dirs?
|
||||
# TODO: main() should create those dirs, c.f. #902
|
||||
os.makedirs(os.path.join(self.tempdir, "live", "example.org"))
|
||||
archive_path = os.path.join(self.tempdir, "archive", "example.org")
|
||||
os.makedirs(os.path.join(self.config.config_dir, "live", "example.org"))
|
||||
archive_path = os.path.join(self.config.config_dir, "archive", "example.org")
|
||||
os.makedirs(archive_path)
|
||||
os.makedirs(os.path.join(self.tempdir, "renewal"))
|
||||
os.makedirs(os.path.join(self.config.config_dir, "renewal"))
|
||||
|
||||
config = configobj.ConfigObj()
|
||||
config_file = configobj.ConfigObj()
|
||||
for kind in ALL_FOUR:
|
||||
kind_path = os.path.join(self.tempdir, "live", "example.org",
|
||||
kind_path = os.path.join(self.config.config_dir, "live", "example.org",
|
||||
kind + ".pem")
|
||||
config[kind] = kind_path
|
||||
with open(os.path.join(self.tempdir, "live", "example.org",
|
||||
config_file[kind] = kind_path
|
||||
with open(os.path.join(self.config.config_dir, "live", "example.org",
|
||||
"README"), 'a'):
|
||||
pass
|
||||
config["archive"] = archive_path
|
||||
config.filename = os.path.join(self.tempdir, "renewal",
|
||||
config_file["archive"] = archive_path
|
||||
config_file.filename = os.path.join(self.config.config_dir, "renewal",
|
||||
"example.org.conf")
|
||||
config.write()
|
||||
self.config = config
|
||||
config_file.write()
|
||||
self.config_file = config_file
|
||||
|
||||
# We also create a file that isn't a renewal config in the same
|
||||
# location to test that logic that reads in all-and-only renewal
|
||||
# configs will ignore it and NOT attempt to parse it.
|
||||
junk = open(os.path.join(self.tempdir, "renewal", "IGNORE.THIS"), "w")
|
||||
junk = open(os.path.join(self.config.config_dir, "renewal", "IGNORE.THIS"), "w")
|
||||
junk.write("This file should be ignored!")
|
||||
junk.close()
|
||||
|
||||
|
|
@ -90,7 +82,7 @@ class BaseRenewableCertTest(util.TempDirTestCase):
|
|||
|
||||
with mock.patch("certbot.storage.RenewableCert._check_symlinks") as check:
|
||||
check.return_value = True
|
||||
self.test_rc = storage.RenewableCert(config.filename, self.cli_config)
|
||||
self.test_rc = storage.RenewableCert(config_file.filename, self.config)
|
||||
|
||||
def _write_out_kind(self, kind, ver, value=None):
|
||||
link = getattr(self.test_rc, kind)
|
||||
|
|
@ -117,7 +109,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
for kind in ALL_FOUR:
|
||||
self.assertEqual(
|
||||
getattr(self.test_rc, kind), os.path.join(
|
||||
self.tempdir, "live", "example.org", kind + ".pem"))
|
||||
self.config.config_dir, "live", "example.org", kind + ".pem"))
|
||||
|
||||
def test_renewal_bad_config(self):
|
||||
"""Test that the RenewableCert constructor will complain if
|
||||
|
|
@ -125,14 +117,14 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
|
||||
"""
|
||||
from certbot import storage
|
||||
broken = os.path.join(self.tempdir, "broken.conf")
|
||||
broken = os.path.join(self.config.config_dir, "broken.conf")
|
||||
with open(broken, "w") as f:
|
||||
f.write("[No closing bracket for you!")
|
||||
self.assertRaises(errors.CertStorageError, storage.RenewableCert,
|
||||
broken, self.cli_config)
|
||||
broken, self.config)
|
||||
os.unlink(broken)
|
||||
self.assertRaises(errors.CertStorageError, storage.RenewableCert,
|
||||
"fun", self.cli_config)
|
||||
"fun", self.config)
|
||||
|
||||
def test_renewal_incomplete_config(self):
|
||||
"""Test that the RenewableCert constructor will complain if
|
||||
|
|
@ -143,30 +135,30 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
# Here the required privkey is missing.
|
||||
config["chain"] = "imaginary_chain.pem"
|
||||
config["fullchain"] = "imaginary_fullchain.pem"
|
||||
config.filename = os.path.join(self.tempdir, "imaginary_config.conf")
|
||||
config.filename = os.path.join(self.config.config_dir, "imaginary_config.conf")
|
||||
config.write()
|
||||
self.assertRaises(errors.CertStorageError, storage.RenewableCert,
|
||||
config.filename, self.cli_config)
|
||||
config.filename, self.config)
|
||||
|
||||
def test_no_renewal_version(self):
|
||||
from certbot import storage
|
||||
|
||||
self._write_out_ex_kinds()
|
||||
self.assertTrue("version" not in self.config)
|
||||
self.assertTrue("version" not in self.config_file)
|
||||
|
||||
with mock.patch("certbot.storage.logger") as mock_logger:
|
||||
storage.RenewableCert(self.config.filename, self.cli_config)
|
||||
storage.RenewableCert(self.config_file.filename, self.config)
|
||||
self.assertFalse(mock_logger.warning.called)
|
||||
|
||||
def test_renewal_newer_version(self):
|
||||
from certbot import storage
|
||||
|
||||
self._write_out_ex_kinds()
|
||||
self.config["version"] = "99.99.99"
|
||||
self.config.write()
|
||||
self.config_file["version"] = "99.99.99"
|
||||
self.config_file.write()
|
||||
|
||||
with mock.patch("certbot.storage.logger") as mock_logger:
|
||||
storage.RenewableCert(self.config.filename, self.cli_config)
|
||||
storage.RenewableCert(self.config_file.filename, self.config)
|
||||
self.assertTrue(mock_logger.warning.called)
|
||||
self.assertTrue("version" in mock_logger.warning.call_args[0][0])
|
||||
|
||||
|
|
@ -191,7 +183,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
unlink_all(self.test_rc)
|
||||
# Items must point to desired place if they are absolute
|
||||
for kind in ALL_FOUR:
|
||||
os.symlink(os.path.join(self.tempdir, kind + "17.pem"),
|
||||
os.symlink(os.path.join(self.config.config_dir, kind + "17.pem"),
|
||||
getattr(self.test_rc, kind))
|
||||
self.assertFalse(self.test_rc._consistent())
|
||||
unlink_all(self.test_rc)
|
||||
|
|
@ -216,17 +208,17 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
# Relative path logic
|
||||
self._write_out_kind("cert", 17)
|
||||
self.assertTrue(os.path.samefile(self.test_rc.current_target("cert"),
|
||||
os.path.join(self.tempdir, "archive",
|
||||
os.path.join(self.config.config_dir, "archive",
|
||||
"example.org",
|
||||
"cert17.pem")))
|
||||
# Absolute path logic
|
||||
os.unlink(self.test_rc.cert)
|
||||
os.symlink(os.path.join(self.tempdir, "archive", "example.org",
|
||||
os.symlink(os.path.join(self.config.config_dir, "archive", "example.org",
|
||||
"cert17.pem"), self.test_rc.cert)
|
||||
with open(self.test_rc.cert, "w") as f:
|
||||
f.write("cert")
|
||||
self.assertTrue(os.path.samefile(self.test_rc.current_target("cert"),
|
||||
os.path.join(self.tempdir, "archive",
|
||||
os.path.join(self.config.config_dir, "archive",
|
||||
"example.org",
|
||||
"cert17.pem")))
|
||||
|
||||
|
|
@ -369,18 +361,21 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
|
||||
def test_names(self):
|
||||
# Trying the current version
|
||||
self._write_out_kind("cert", 12, util.load_vector("cert-san.pem"))
|
||||
self._write_out_kind("cert", 12, test_util.load_vector("cert-san_512.pem"))
|
||||
|
||||
self.assertEqual(self.test_rc.names(),
|
||||
["example.com", "www.example.com"])
|
||||
|
||||
# Trying a non-current version
|
||||
self._write_out_kind("cert", 15, util.load_vector("cert.pem"))
|
||||
self._write_out_kind("cert", 15, test_util.load_vector("cert_512.pem"))
|
||||
|
||||
self.assertEqual(self.test_rc.names(12),
|
||||
["example.com", "www.example.com"])
|
||||
|
||||
# Testing common name is listed first
|
||||
self._write_out_kind(
|
||||
"cert", 12, util.load_vector("cert-5sans.pem"))
|
||||
"cert", 12, test_util.load_vector("cert-5sans_512.pem"))
|
||||
|
||||
self.assertEqual(
|
||||
self.test_rc.names(12),
|
||||
["example.com"] + ["{0}.example.com".format(c) for c in "abcd"])
|
||||
|
|
@ -393,7 +388,8 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
def test_time_interval_judgments(self, mock_datetime):
|
||||
"""Test should_autodeploy() and should_autorenew() on the basis
|
||||
of expiry time windows."""
|
||||
test_cert = util.load_vector("cert.pem")
|
||||
test_cert = test_util.load_vector("cert_512.pem")
|
||||
|
||||
self._write_out_ex_kinds()
|
||||
|
||||
self.test_rc.update_all_links_to(12)
|
||||
|
|
@ -491,7 +487,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self.test_rc.update_all_links_to(3)
|
||||
self.assertEqual(
|
||||
6, self.test_rc.save_successor(3, b'new cert', None,
|
||||
b'new chain', self.cli_config))
|
||||
b'new chain', self.config))
|
||||
with open(self.test_rc.version("cert", 6)) as f:
|
||||
self.assertEqual(f.read(), "new cert")
|
||||
with open(self.test_rc.version("chain", 6)) as f:
|
||||
|
|
@ -504,10 +500,10 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
# Let's try two more updates
|
||||
self.assertEqual(
|
||||
7, self.test_rc.save_successor(6, b'again', None,
|
||||
b'newer chain', self.cli_config))
|
||||
b'newer chain', self.config))
|
||||
self.assertEqual(
|
||||
8, self.test_rc.save_successor(7, b'hello', None,
|
||||
b'other chain', self.cli_config))
|
||||
b'other chain', self.config))
|
||||
# All of the subsequent versions should link directly to the original
|
||||
# privkey.
|
||||
for i in (6, 7, 8):
|
||||
|
|
@ -522,14 +518,14 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
self.test_rc.update_all_links_to(8)
|
||||
self.assertEqual(
|
||||
9, self.test_rc.save_successor(8, b'last', None,
|
||||
b'attempt', self.cli_config))
|
||||
b'attempt', self.config))
|
||||
for kind in ALL_FOUR:
|
||||
self.assertEqual(self.test_rc.available_versions(kind),
|
||||
list(six.moves.range(1, 10)))
|
||||
self.assertEqual(self.test_rc.current_version(kind), 8)
|
||||
with open(self.test_rc.version("fullchain", 9)) as f:
|
||||
self.assertEqual(f.read(), "last" + "attempt")
|
||||
temp_config_file = os.path.join(self.cli_config.renewal_configs_dir,
|
||||
temp_config_file = os.path.join(self.config.renewal_configs_dir,
|
||||
self.test_rc.lineagename) + ".conf.new"
|
||||
with open(temp_config_file, "w") as f:
|
||||
f.write("We previously crashed while writing me :(")
|
||||
|
|
@ -537,7 +533,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
# be saved in a new file rather than creating a new symlink.
|
||||
self.assertEqual(
|
||||
10, self.test_rc.save_successor(9, b'with', b'a',
|
||||
b'key', self.cli_config))
|
||||
b'key', self.config))
|
||||
self.assertTrue(os.path.exists(self.test_rc.version("privkey", 10)))
|
||||
self.assertFalse(os.path.islink(self.test_rc.version("privkey", 10)))
|
||||
self.assertFalse(os.path.exists(temp_config_file))
|
||||
|
|
@ -597,38 +593,38 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
|
||||
from certbot import storage
|
||||
result = storage.RenewableCert.new_lineage(
|
||||
"the-lineage.com", b"cert", b"privkey", b"chain", self.cli_config)
|
||||
"the-lineage.com", b"cert", b"privkey", b"chain", self.config)
|
||||
# This consistency check tests most relevant properties about the
|
||||
# newly created cert lineage.
|
||||
# pylint: disable=protected-access
|
||||
self.assertTrue(result._consistent())
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.renewal_configs_dir, "the-lineage.com.conf")))
|
||||
self.config.renewal_configs_dir, "the-lineage.com.conf")))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "the-lineage.com", "README")))
|
||||
self.config.live_dir, "the-lineage.com", "README")))
|
||||
with open(result.fullchain, "rb") as f:
|
||||
self.assertEqual(f.read(), b"cert" + b"chain")
|
||||
# Let's do it again and make sure it makes a different lineage
|
||||
result = storage.RenewableCert.new_lineage(
|
||||
"the-lineage.com", b"cert2", b"privkey2", b"chain2", self.cli_config)
|
||||
"the-lineage.com", b"cert2", b"privkey2", b"chain2", self.config)
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.renewal_configs_dir, "the-lineage.com-0001.conf")))
|
||||
self.config.renewal_configs_dir, "the-lineage.com-0001.conf")))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "the-lineage.com-0001", "README")))
|
||||
self.config.live_dir, "the-lineage.com-0001", "README")))
|
||||
# Now trigger the detection of already existing files
|
||||
os.mkdir(os.path.join(
|
||||
self.cli_config.live_dir, "the-lineage.com-0002"))
|
||||
self.config.live_dir, "the-lineage.com-0002"))
|
||||
self.assertRaises(errors.CertStorageError,
|
||||
storage.RenewableCert.new_lineage, "the-lineage.com",
|
||||
b"cert3", b"privkey3", b"chain3", self.cli_config)
|
||||
os.mkdir(os.path.join(self.cli_config.default_archive_dir, "other-example.com"))
|
||||
b"cert3", b"privkey3", b"chain3", self.config)
|
||||
os.mkdir(os.path.join(self.config.default_archive_dir, "other-example.com"))
|
||||
self.assertRaises(errors.CertStorageError,
|
||||
storage.RenewableCert.new_lineage,
|
||||
"other-example.com", b"cert4",
|
||||
b"privkey4", b"chain4", self.cli_config)
|
||||
b"privkey4", b"chain4", self.config)
|
||||
# Make sure it can accept renewal parameters
|
||||
result = storage.RenewableCert.new_lineage(
|
||||
"the-lineage.com", b"cert2", b"privkey2", b"chain2", self.cli_config)
|
||||
"the-lineage.com", b"cert2", b"privkey2", b"chain2", self.config)
|
||||
# TODO: Conceivably we could test that the renewal parameters actually
|
||||
# got saved
|
||||
|
||||
|
|
@ -640,19 +636,19 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
mock_rv.side_effect = lambda x: x
|
||||
|
||||
from certbot import storage
|
||||
shutil.rmtree(self.cli_config.renewal_configs_dir)
|
||||
shutil.rmtree(self.cli_config.default_archive_dir)
|
||||
shutil.rmtree(self.cli_config.live_dir)
|
||||
shutil.rmtree(self.config.renewal_configs_dir)
|
||||
shutil.rmtree(self.config.default_archive_dir)
|
||||
shutil.rmtree(self.config.live_dir)
|
||||
|
||||
storage.RenewableCert.new_lineage(
|
||||
"the-lineage.com", b"cert2", b"privkey2", b"chain2", self.cli_config)
|
||||
"the-lineage.com", b"cert2", b"privkey2", b"chain2", self.config)
|
||||
self.assertTrue(os.path.exists(
|
||||
os.path.join(
|
||||
self.cli_config.renewal_configs_dir, "the-lineage.com.conf")))
|
||||
self.config.renewal_configs_dir, "the-lineage.com.conf")))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "the-lineage.com", "privkey.pem")))
|
||||
self.config.live_dir, "the-lineage.com", "privkey.pem")))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.default_archive_dir, "the-lineage.com", "privkey1.pem")))
|
||||
self.config.default_archive_dir, "the-lineage.com", "privkey1.pem")))
|
||||
|
||||
@mock.patch("certbot.storage.util.unique_lineage_name")
|
||||
def test_invalid_config_filename(self, mock_uln):
|
||||
|
|
@ -660,7 +656,7 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
mock_uln.return_value = "this_does_not_end_with_dot_conf", "yikes"
|
||||
self.assertRaises(errors.CertStorageError,
|
||||
storage.RenewableCert.new_lineage, "example.com",
|
||||
"cert", "privkey", "chain", self.cli_config)
|
||||
"cert", "privkey", "chain", self.config)
|
||||
|
||||
def test_bad_kind(self):
|
||||
self.assertRaises(
|
||||
|
|
@ -744,18 +740,18 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
from certbot import storage
|
||||
self.assertRaises(errors.CertStorageError,
|
||||
storage.RenewableCert,
|
||||
self.config.filename, self.cli_config)
|
||||
os.symlink("missing", self.config[ALL_FOUR[0]])
|
||||
self.config_file.filename, self.config)
|
||||
os.symlink("missing", self.config_file[ALL_FOUR[0]])
|
||||
self.assertRaises(errors.CertStorageError,
|
||||
storage.RenewableCert,
|
||||
self.config.filename, self.cli_config)
|
||||
self.config_file.filename, self.config)
|
||||
|
||||
def test_write_renewal_config(self):
|
||||
# Mostly tested by the process of creating and updating lineages,
|
||||
# but we can test that this successfully creates files, removes
|
||||
# unneeded items, and preserves comments.
|
||||
temp = os.path.join(self.tempdir, "sample-file")
|
||||
temp2 = os.path.join(self.tempdir, "sample-file.new")
|
||||
temp = os.path.join(self.config.config_dir, "sample-file")
|
||||
temp2 = os.path.join(self.config.config_dir, "sample-file.new")
|
||||
with open(temp, "w") as f:
|
||||
f.write("[renewalparams]\nuseful = value # A useful value\n"
|
||||
"useless = value # Not needed\n")
|
||||
|
|
@ -785,17 +781,17 @@ class RenewableCertTests(BaseRenewableCertTest):
|
|||
|
||||
def test_update_symlinks(self):
|
||||
from certbot import storage
|
||||
archive_dir_path = os.path.join(self.tempdir, "archive", "example.org")
|
||||
archive_dir_path = os.path.join(self.config.config_dir, "archive", "example.org")
|
||||
for kind in ALL_FOUR:
|
||||
live_path = self.config[kind]
|
||||
live_path = self.config_file[kind]
|
||||
basename = kind + "1.pem"
|
||||
archive_path = os.path.join(archive_dir_path, basename)
|
||||
open(archive_path, 'a').close()
|
||||
os.symlink(os.path.join(self.tempdir, basename), live_path)
|
||||
os.symlink(os.path.join(self.config.config_dir, basename), live_path)
|
||||
self.assertRaises(errors.CertStorageError,
|
||||
storage.RenewableCert, self.config.filename,
|
||||
self.cli_config)
|
||||
storage.RenewableCert(self.config.filename, self.cli_config,
|
||||
storage.RenewableCert, self.config_file.filename,
|
||||
self.config)
|
||||
storage.RenewableCert(self.config_file.filename, self.config,
|
||||
update_symlinks=True)
|
||||
|
||||
class DeleteFilesTest(BaseRenewableCertTest):
|
||||
|
|
@ -804,88 +800,88 @@ class DeleteFilesTest(BaseRenewableCertTest):
|
|||
super(DeleteFilesTest, self).setUp()
|
||||
|
||||
for kind in ALL_FOUR:
|
||||
kind_path = os.path.join(self.tempdir, "live", "example.org",
|
||||
kind_path = os.path.join(self.config.config_dir, "live", "example.org",
|
||||
kind + ".pem")
|
||||
with open(kind_path, 'a'):
|
||||
pass
|
||||
self.config.write()
|
||||
self.config_file.write()
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.renewal_configs_dir, "example.org.conf")))
|
||||
self.config.renewal_configs_dir, "example.org.conf")))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "example.org")))
|
||||
self.config.live_dir, "example.org")))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.tempdir, "archive", "example.org")))
|
||||
self.config.config_dir, "archive", "example.org")))
|
||||
|
||||
def _call(self):
|
||||
from certbot import storage
|
||||
with mock.patch("certbot.storage.logger"):
|
||||
storage.delete_files(self.cli_config, "example.org")
|
||||
storage.delete_files(self.config, "example.org")
|
||||
|
||||
def test_delete_all_files(self):
|
||||
self._call()
|
||||
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.cli_config.renewal_configs_dir, "example.org.conf")))
|
||||
self.config.renewal_configs_dir, "example.org.conf")))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "example.org")))
|
||||
self.config.live_dir, "example.org")))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.tempdir, "archive", "example.org")))
|
||||
self.config.config_dir, "archive", "example.org")))
|
||||
|
||||
def test_bad_renewal_config(self):
|
||||
with open(self.config.filename, 'a') as config_file:
|
||||
with open(self.config_file.filename, 'a') as config_file:
|
||||
config_file.write("asdfasfasdfasdf")
|
||||
|
||||
self.assertRaises(errors.CertStorageError, self._call)
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "example.org")))
|
||||
self.config.live_dir, "example.org")))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.cli_config.renewal_configs_dir, "example.org.conf")))
|
||||
self.config.renewal_configs_dir, "example.org.conf")))
|
||||
|
||||
def test_no_renewal_config(self):
|
||||
os.remove(self.config.filename)
|
||||
os.remove(self.config_file.filename)
|
||||
self.assertRaises(errors.CertStorageError, self._call)
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "example.org")))
|
||||
self.assertFalse(os.path.exists(self.config.filename))
|
||||
self.config.live_dir, "example.org")))
|
||||
self.assertFalse(os.path.exists(self.config_file.filename))
|
||||
|
||||
def test_no_cert_file(self):
|
||||
os.remove(os.path.join(
|
||||
self.cli_config.live_dir, "example.org", "cert.pem"))
|
||||
self.config.live_dir, "example.org", "cert.pem"))
|
||||
self._call()
|
||||
self.assertFalse(os.path.exists(self.config.filename))
|
||||
self.assertFalse(os.path.exists(self.config_file.filename))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "example.org")))
|
||||
self.config.live_dir, "example.org")))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.tempdir, "archive", "example.org")))
|
||||
self.config.config_dir, "archive", "example.org")))
|
||||
|
||||
def test_no_readme_file(self):
|
||||
os.remove(os.path.join(
|
||||
self.cli_config.live_dir, "example.org", "README"))
|
||||
self.config.live_dir, "example.org", "README"))
|
||||
self._call()
|
||||
self.assertFalse(os.path.exists(self.config.filename))
|
||||
self.assertFalse(os.path.exists(self.config_file.filename))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "example.org")))
|
||||
self.config.live_dir, "example.org")))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.tempdir, "archive", "example.org")))
|
||||
self.config.config_dir, "archive", "example.org")))
|
||||
|
||||
def test_livedir_not_empty(self):
|
||||
with open(os.path.join(
|
||||
self.cli_config.live_dir, "example.org", "other_file"), 'a'):
|
||||
self.config.live_dir, "example.org", "other_file"), 'a'):
|
||||
pass
|
||||
self._call()
|
||||
self.assertFalse(os.path.exists(self.config.filename))
|
||||
self.assertFalse(os.path.exists(self.config_file.filename))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "example.org")))
|
||||
self.config.live_dir, "example.org")))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.tempdir, "archive", "example.org")))
|
||||
self.config.config_dir, "archive", "example.org")))
|
||||
|
||||
def test_no_archive(self):
|
||||
archive_dir = os.path.join(self.tempdir, "archive", "example.org")
|
||||
archive_dir = os.path.join(self.config.config_dir, "archive", "example.org")
|
||||
os.rmdir(archive_dir)
|
||||
self._call()
|
||||
self.assertFalse(os.path.exists(self.config.filename))
|
||||
self.assertFalse(os.path.exists(self.config_file.filename))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.cli_config.live_dir, "example.org")))
|
||||
self.config.live_dir, "example.org")))
|
||||
self.assertFalse(os.path.exists(archive_dir))
|
||||
|
||||
|
||||
|
|
|
|||
11
certbot/tests/testdata/README
vendored
Normal file
11
certbot/tests/testdata/README
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
The following command has been used to generate test keys:
|
||||
|
||||
for x in 256 512 2048; do openssl genrsa -out rsa${k}_key.pem $k; done
|
||||
|
||||
and for the CSR PEM (Certificate Signing Request):
|
||||
|
||||
openssl req -new -out csr-Xsans_X.pem -key rsa512_key.pem [-config csr-Xsans_X.conf | -subj '/CN=example.com'] [-outform DER > csr_X.der]
|
||||
|
||||
and for the certificate:
|
||||
|
||||
openssl req -new -out cert_X.pem -key rsaX_key.pem -subj '/CN=example.com' -x509 [-outform DER > cert_X.der]
|
||||
1
certbot/tests/testdata/cert.b64jose
vendored
1
certbot/tests/testdata/cert.b64jose
vendored
|
|
@ -1 +0,0 @@
|
|||
MIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR7R_drnBSQ_zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c-pVE6K-EdE_twuUCAwEAATANBgkqhkiG9w0BAQsFAANBAC24z0IdwIVKSlntksllvr6zJepBH5fMndfk3XJp10jT6VE-14KNtjh02a56GoraAvJAT5_H67E8GvJ_ocNnB_o
|
||||
BIN
certbot/tests/testdata/cert.der
vendored
BIN
certbot/tests/testdata/cert.der
vendored
Binary file not shown.
12
certbot/tests/testdata/csr-6sans.pem
vendored
12
certbot/tests/testdata/csr-6sans.pem
vendored
|
|
@ -1,12 +0,0 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBuzCCAWUCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE1pY2hpZ2FuMRIw
|
||||
EAYDVQQHEwlBbm4gQXJib3IxDDAKBgNVBAoTA0VGRjEfMB0GA1UECxMWVW5pdmVy
|
||||
c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wXDANBgkqhkiG
|
||||
9w0BAQEFAANLADBIAkEA9LYRcVE3Nr+qleecEcX8JwVDnjeG1X7ucsCasuuZM0e0
|
||||
9cmYuUzxIkMjO/9x4AVcvXXRXPEV+LzWWkfkTlzRMwIDAQABoIGGMIGDBgkqhkiG
|
||||
9w0BCQ4xdjB0MHIGA1UdEQRrMGmCC2V4YW1wbGUuY29tggtleGFtcGxlLm9yZ4IL
|
||||
ZXhhbXBsZS5uZXSCDGV4YW1wbGUuaW5mb4IVc3ViZG9tYWluLmV4YW1wbGUuY29t
|
||||
ghtvdGhlci5zdWJkb21haW4uZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADQQBd
|
||||
k4BE5qvEvkYoZM/2++Xd9RrQ6wsdj0QiJQCozfsI4lQx6ZJnbtNc7HpDrX4W6XIv
|
||||
IvzVBz/nD11drfz/RNuX
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
29
certbot/tests/testdata/csr-6sans_512.conf
vendored
Normal file
29
certbot/tests/testdata/csr-6sans_512.conf
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
|
||||
[req_distinguished_name]
|
||||
C=US
|
||||
C_default = US
|
||||
ST=Michigan
|
||||
ST_default=Michigan
|
||||
L=Ann Arbor
|
||||
L_default=Ann Arbor
|
||||
O=EFF
|
||||
O_default=EFF
|
||||
OU=University of Michigan
|
||||
OU_default=University of Michigan
|
||||
CN=example.com
|
||||
CN_default=example.com
|
||||
|
||||
|
||||
[ v3_req ]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = example.com
|
||||
DNS.2 = example.org
|
||||
DNS.3 = example.net
|
||||
DNS.4 = example.info
|
||||
DNS.5 = subdomain.example.com
|
||||
DNS.6 = other.subdomain.example.com
|
||||
12
certbot/tests/testdata/csr-6sans_512.pem
vendored
Normal file
12
certbot/tests/testdata/csr-6sans_512.pem
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBuzCCAWUCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw
|
||||
EAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECwwWVW5pdmVy
|
||||
c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wXDANBgkqhkiG
|
||||
9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3f
|
||||
p580rv2+6QWE30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABoIGGMIGDBgkqhkiG
|
||||
9w0BCQ4xdjB0MHIGA1UdEQRrMGmCC2V4YW1wbGUuY29tggtleGFtcGxlLm9yZ4IL
|
||||
ZXhhbXBsZS5uZXSCDGV4YW1wbGUuaW5mb4IVc3ViZG9tYWluLmV4YW1wbGUuY29t
|
||||
ghtvdGhlci5zdWJkb21haW4uZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADQQA+
|
||||
sU6T30n3SsdnHlj0Va8eECOWK7Lf8nUfxxgjPMQ7BoU8gbAnGfDmOlwDronTRqf1
|
||||
Me+nlYJU4TX1OiX10DYu
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
8
certbot/tests/testdata/csr-nosans.pem
vendored
8
certbot/tests/testdata/csr-nosans.pem
vendored
|
|
@ -1,8 +0,0 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBFTCBwAIBADBbMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
|
||||
MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQDDAtleGFt
|
||||
cGxlLm9yZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQD0thFxUTc2v6qV55wRxfwn
|
||||
BUOeN4bVfu5ywJqy65kzR7T1yZi5TPEiQyM7/3HgBVy9ddFc8RX4vNZaR+ROXNEz
|
||||
AgMBAAGgADANBgkqhkiG9w0BAQsFAANBAMikGL8Ch7hQCStXH7chhDp6+pt2+VSo
|
||||
wgsrPQ2Bw4veDMlSemUrH+4e0TwbbntHfvXTDHWs9P3BiIDJLxFrjuA=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
16
certbot/tests/testdata/csr-nosans_512.conf
vendored
Normal file
16
certbot/tests/testdata/csr-nosans_512.conf
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
|
||||
[req_distinguished_name]
|
||||
C=US
|
||||
C_default = US
|
||||
ST=Michigan
|
||||
ST_default=Michigan
|
||||
L=Ann Arbor
|
||||
L_default=Ann Arbor
|
||||
O=EFF
|
||||
O_default=EFF
|
||||
OU=University of Michigan
|
||||
OU_default=University of Michigan
|
||||
CN=example.com
|
||||
CN_default=example.com
|
||||
9
certbot/tests/testdata/csr-nosans_512.pem
vendored
Normal file
9
certbot/tests/testdata/csr-nosans_512.pem
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBMzCB3gIBADB5MQswCQYDVQQGEwJVUzERMA8GA1UECAwITWljaGlnYW4xEjAQ
|
||||
BgNVBAcMCUFubiBBcmJvcjEMMAoGA1UECgwDRUZGMR8wHQYDVQQLDBZVbml2ZXJz
|
||||
aXR5IHBmIE1pY2hpZ2FuMRQwEgYDVQQDDAtleGFtcGxlLmNvbTBcMA0GCSqGSIb3
|
||||
DQEBAQUAA0sAMEgCQQCsdXO0Ue0f3a5wUkP838db0Cx1GxS4dQEEEOUfA2VF3d+n
|
||||
nzSu/b7pBYTfRxaB2YlLzo5tHPqVROivhHRP7cLlAgMBAAGgADANBgkqhkiG9w0B
|
||||
AQsFAANBAG06jIPvSC6wiGLy7sUTaEX4UCE6Cztp3vh/uXN7Q++CGn6KiXNs/BRW
|
||||
eFlcFPbvxbVG/ZZFR5aPs+Oy6RhqOjg=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
14
certbot/tests/testdata/dsa512_key.pem
vendored
14
certbot/tests/testdata/dsa512_key.pem
vendored
|
|
@ -1,14 +0,0 @@
|
|||
-----BEGIN DSA PARAMETERS-----
|
||||
MIGdAkEAwebEoGBfokKQeALHHnAZMQwYU35ILEBdV8oUmzv7qpSVUoHihyqfn6GC
|
||||
OixAKSP8EJYcTilIqPbFbfFyOPlbLwIVANoFHEDiQgknAvKrG78pHzAJdQSPAkEA
|
||||
qfka5Bnl+CeEMpzVZGrOVqZE/LFdZK9eT6YtWjzqtIkf3hwXUVxJsTnBG4xmrfvl
|
||||
41pgNJpgu99YOYqPpS0g7A==
|
||||
-----END DSA PARAMETERS-----
|
||||
-----BEGIN DSA PRIVATE KEY-----
|
||||
MIH5AgEAAkEAwebEoGBfokKQeALHHnAZMQwYU35ILEBdV8oUmzv7qpSVUoHihyqf
|
||||
n6GCOixAKSP8EJYcTilIqPbFbfFyOPlbLwIVANoFHEDiQgknAvKrG78pHzAJdQSP
|
||||
AkEAqfka5Bnl+CeEMpzVZGrOVqZE/LFdZK9eT6YtWjzqtIkf3hwXUVxJsTnBG4xm
|
||||
rfvl41pgNJpgu99YOYqPpS0g7AJATQ2LUzjGQSM6UljcPY5I2OD9THkUR9kH2tth
|
||||
zZd70UoI9btrVaTizgqYShuok94glSQNK0H92JgUk3scJPaAkAIVAMDn61h6vrCE
|
||||
mNv063So6E+eYaIN
|
||||
-----END DSA PRIVATE KEY-----
|
||||
17
certbot/tests/testdata/dsa_cert.pem
vendored
17
certbot/tests/testdata/dsa_cert.pem
vendored
|
|
@ -1,17 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICuDCCAnWgAwIBAgIJAPjmErVMzwVLMAsGCWCGSAFlAwQDAjB3MQswCQYDVQQG
|
||||
EwJVUzERMA8GA1UECAwITWljaGlnYW4xEjAQBgNVBAcMCUFubiBBcmJvcjErMCkG
|
||||
A1UECgwiVW5pdmVyc2l0eSBvZiBNaWNoaWdhbiBhbmQgdGhlIEVGRjEUMBIGA1UE
|
||||
AwwLZXhhbXBsZS5jb20wHhcNMTUwNTEyMTUzOTQzWhcNMTUwNjExMTUzOTQzWjB3
|
||||
MQswCQYDVQQGEwJVUzERMA8GA1UECAwITWljaGlnYW4xEjAQBgNVBAcMCUFubiBB
|
||||
cmJvcjErMCkGA1UECgwiVW5pdmVyc2l0eSBvZiBNaWNoaWdhbiBhbmQgdGhlIEVG
|
||||
RjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wgfEwgakGByqGSM44BAEwgZ0CQQDB5sSg
|
||||
YF+iQpB4AscecBkxDBhTfkgsQF1XyhSbO/uqlJVSgeKHKp+foYI6LEApI/wQlhxO
|
||||
KUio9sVt8XI4+VsvAhUA2gUcQOJCCScC8qsbvykfMAl1BI8CQQCp+RrkGeX4J4Qy
|
||||
nNVkas5WpkT8sV1kr15Ppi1aPOq0iR/eHBdRXEmxOcEbjGat++XjWmA0mmC731g5
|
||||
io+lLSDsA0MAAkBNDYtTOMZBIzpSWNw9jkjY4P1MeRRH2Qfa22HNl3vRSgj1u2tV
|
||||
pOLOCphKG6iT3iCVJA0rQf3YmBSTexwk9oCQo1AwTjAdBgNVHQ4EFgQUZ2DlTDGU
|
||||
PMwTUt0KztM6IyX61BcwHwYDVR0jBBgwFoAUZ2DlTDGUPMwTUt0KztM6IyX61Bcw
|
||||
DAYDVR0TBAUwAwEB/zALBglghkgBZQMEAwIDMAAwLQIVAIbMgGx+KwBr4rgqZ2Lh
|
||||
AAO8TegHAhQsuxpIIIphiReoWEtEJk4TqEIz/A==
|
||||
-----END CERTIFICATE-----
|
||||
14
certbot/tests/testdata/matching_cert.pem
vendored
14
certbot/tests/testdata/matching_cert.pem
vendored
|
|
@ -1,14 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICNzCCAeGgAwIBAgIJALizm9Y3q620MA0GCSqGSIb3DQEBCwUAMHcxCzAJBgNV
|
||||
BAYTAlVTMREwDwYDVQQIDAhNaWNoaWdhbjESMBAGA1UEBwwJQW5uIEFyYm9yMSsw
|
||||
KQYDVQQKDCJVbml2ZXJzaXR5IG9mIE1pY2hpZ2FuIGFuZCB0aGUgRUZGMRQwEgYD
|
||||
VQQDDAtleGFtcGxlLmNvbTAeFw0xNTA1MDkwMDI0NTJaFw0xNjA1MDgwMDI0NTJa
|
||||
MHcxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNaWNoaWdhbjESMBAGA1UEBwwJQW5u
|
||||
IEFyYm9yMSswKQYDVQQKDCJVbml2ZXJzaXR5IG9mIE1pY2hpZ2FuIGFuZCB0aGUg
|
||||
RUZGMRQwEgYDVQQDDAtleGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgC
|
||||
QQD0thFxUTc2v6qV55wRxfwnBUOeN4bVfu5ywJqy65kzR7T1yZi5TPEiQyM7/3Hg
|
||||
BVy9ddFc8RX4vNZaR+ROXNEzAgMBAAGjUDBOMB0GA1UdDgQWBBRJieHEVSHKmBk0
|
||||
mTExx1erzlylCjAfBgNVHSMEGDAWgBRJieHEVSHKmBk0mTExx1erzlylCjAMBgNV
|
||||
HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EABT/nlpqOaanFSLZmWIrKv0zt63k4
|
||||
bmWNMA8fYT45KYpLomsW8qXdpC82IlVKfNk7fW0UYT3HOeDSJRcycxNCTQ==
|
||||
-----END CERTIFICATE-----
|
||||
9
certbot/tests/testdata/rsa512_key_2.pem
vendored
9
certbot/tests/testdata/rsa512_key_2.pem
vendored
|
|
@ -1,9 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBOwIBAAJBAPS2EXFRNza/qpXnnBHF/CcFQ543htV+7nLAmrLrmTNHtPXJmLlM
|
||||
8SJDIzv/ceAFXL110VzxFfi81lpH5E5c0TMCAwEAAQJBALmppYQ/JVARjWBcsEm/
|
||||
1/bXBJ127YLv4gQIY5baL4r6IdEE33OXMTTmD9wf+ajuq1eaH0htHkwhOvREu0sz
|
||||
bskCIQD/Cg+xhEVLcwK3pFp3afPIhj1IPFiL3Uy/nqyMZ6O/RQIhAPWiDBofp7Cp
|
||||
J4dGZs+hkRySq/IOeeRJlNK1Pq64nToXAiBZ7+te1100YSd5KT051SRB94zO13EG
|
||||
SZESFduVW8rz3QIgK+tLiqg6TYYRQUi/PUTAM4GuKNuZw828RGiPyqHLywUCIQCd
|
||||
pkZrNphL/y0D7HSbPIfZzD90M2V8tUjlK0BTqk1bHA==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -22,6 +22,7 @@ from certbot import constants
|
|||
from certbot import interfaces
|
||||
from certbot import storage
|
||||
from certbot import util
|
||||
from certbot import configuration
|
||||
|
||||
from certbot.display import util as display_util
|
||||
|
||||
|
|
@ -246,6 +247,20 @@ class TempDirTestCase(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
shutil.rmtree(self.tempdir)
|
||||
|
||||
class ConfigTestCase(TempDirTestCase):
|
||||
"""Test class which sets up a NamespaceConfig object.
|
||||
|
||||
"""
|
||||
def setUp(self):
|
||||
super(ConfigTestCase, self).setUp()
|
||||
self.config = configuration.NamespaceConfig(
|
||||
mock.MagicMock(
|
||||
config_dir=os.path.join(self.tempdir, 'config'),
|
||||
work_dir=os.path.join(self.tempdir, 'work'),
|
||||
logs_dir=os.path.join(self.tempdir, 'logs'),
|
||||
server="example.com",
|
||||
)
|
||||
)
|
||||
|
||||
def lock_and_call(func, lock_path):
|
||||
"""Grab a lock for lock_path and call func.
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ TLS-SNI-01 Challenge
|
|||
* When using the Apache plugin, make sure you are running Apache and no other web server on port 443.
|
||||
* When using the NGINX plugin, make sure you are running NGINX and no other web server on port 443.
|
||||
* With either the Apache or NGINX plugin, certbot modifies your web server configuration. If you get
|
||||
an installation error then you have received a certificate but the plugin was unable to modify
|
||||
your web server configuration, meaning that you'll have to install the certificate manually.
|
||||
an error after successfully completing the challenge, then you have received a certificate but the
|
||||
plugin was unable to modify your web server configuration, meaning that you'll have to install the certificate manually.
|
||||
In that case, please file a bug to help us improve certbot!
|
||||
* When using the Standalone plugin, make sure another program is not already listening to port 443 on the server.
|
||||
|
||||
|
|
@ -83,4 +83,3 @@ DNS-01 Challenge
|
|||
* When using the manual plugin, make sure your DNS records are correctly updated;
|
||||
you must be able to make appropriate changes to your DNS zone in order to pass the challenge.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ optional arguments:
|
|||
-v, --verbose This flag can be used multiple times to incrementally
|
||||
increase the verbosity of output, e.g. -vvv. (default:
|
||||
-2)
|
||||
--max-log-backups MAX_LOG_BACKUPS
|
||||
Specifies the maximum number of backup logs that
|
||||
should be kept by Certbot's built in log rotation.
|
||||
Setting this flag to 0 disables log rotation entirely,
|
||||
causing Certbot to always append to the same log file.
|
||||
(default: 1000)
|
||||
-n, --non-interactive, --noninteractive
|
||||
Run without ever asking for user input. This may
|
||||
require additional command line flags; the client will
|
||||
|
|
@ -68,8 +74,8 @@ optional arguments:
|
|||
reloads webservers to deploy and then roll back those
|
||||
changes. It also calls --pre-hook and --post-hook
|
||||
commands if they are defined because they may be
|
||||
necessary to accurately simulate renewal. --renew-hook
|
||||
commands are not called. (default: False)
|
||||
necessary to accurately simulate renewal. --deploy-
|
||||
hook commands are not called. (default: False)
|
||||
--debug-challenges After setting up challenges, wait for user input
|
||||
before submitting to CA (default: False)
|
||||
--preferred-challenges PREF_CHALLS
|
||||
|
|
@ -89,12 +95,18 @@ 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.16.0 (certbot;
|
||||
Ubuntu 16.04.2 LTS) Authenticator/XXX Installer/YYY
|
||||
"". (default: CertbotACMEClient/0.17.0 (certbot;
|
||||
Ubuntu 16.04.3 LTS) Authenticator/XXX Installer/YYY
|
||||
(SUBCOMMAND; flags: FLAGS) Py/2.7.12). The flags
|
||||
encoded in the user agent are: --duplicate, --force-
|
||||
renew, --allow-subset-of-names, -n, and whether any
|
||||
hooks are set.
|
||||
--user-agent-comment USER_AGENT_COMMENT
|
||||
Add a comment to the default user agent string. May be
|
||||
used when repackaging Certbot or calling it from
|
||||
another tool to allow additional statistical data to
|
||||
be collected. Ignored if --user-agent is set.
|
||||
(Example: Foo-Wrapper/1.0) (default: None)
|
||||
|
||||
automation:
|
||||
Arguments for automating execution & other tweaks
|
||||
|
|
@ -274,10 +286,10 @@ renew:
|
|||
attempt was made to obtain/renew a certificate. If
|
||||
multiple renewed certificates have identical post-
|
||||
hooks, only one will be run. (default: None)
|
||||
--renew-hook RENEW_HOOK
|
||||
--deploy-hook DEPLOY_HOOK
|
||||
Command to be run in a shell once for each
|
||||
successfully renewed certificate. For this command,
|
||||
the shell variable $RENEWED_LINEAGE will point to the
|
||||
successfully issued certificate. For this command, the
|
||||
shell variable $RENEWED_LINEAGE will point to the
|
||||
config live subdirectory (for example,
|
||||
"/etc/letsencrypt/live/example.com") containing the
|
||||
new certificates and keys; the shell variable
|
||||
|
|
@ -286,7 +298,7 @@ renew:
|
|||
"example.com www.example.com" (default: None)
|
||||
--disable-hook-validation
|
||||
Ordinarily the commands specified for --pre-hook
|
||||
/--post-hook/--renew-hook will be checked for
|
||||
/--post-hook/--deploy-hook will be checked for
|
||||
validity, to see if the programs being run are in the
|
||||
$PATH, so that mistakes can be caught early, even when
|
||||
the hooks aren't being run just yet. The validation is
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ configurations (if you use the ``apache`` or ``nginx`` plugins). If none of
|
|||
these apply to you, it is theoretically possible to run without root privileges,
|
||||
but for most users who want to avoid running an ACME client as root, either
|
||||
`letsencrypt-nosudo <https://github.com/diafygi/letsencrypt-nosudo>`_ or
|
||||
`simp_le <https://github.com/kuba/simp_le>`_ are more appropriate choices.
|
||||
`simp_le <https://github.com/zenhack/simp_le>`_ are more appropriate choices.
|
||||
|
||||
The Apache plugin currently requires an OS with augeas version 1.0; currently `it
|
||||
supports
|
||||
|
|
@ -234,11 +234,10 @@ Installing from source
|
|||
Installation from source is only supported for developers and the
|
||||
whole process is described in the :doc:`contributing`.
|
||||
|
||||
.. warning:: Please do **not** use ``python setup.py install`` or
|
||||
``python pip install .``. Please do **not** attempt the
|
||||
installation commands as superuser/root and/or without virtual
|
||||
environment, e.g. ``sudo python setup.py install``, ``sudo pip
|
||||
install``, ``sudo ./venv/bin/...``. These modes of operation might
|
||||
corrupt your operating system and are **not supported** by the
|
||||
Certbot team!
|
||||
.. warning:: Please do **not** use ``python setup.py install``, ``python pip
|
||||
install .``, or ``easy_install .``. Please do **not** attempt the
|
||||
installation commands as superuser/root and/or without virtual environment,
|
||||
e.g. ``sudo python setup.py install``, ``sudo pip install``, ``sudo
|
||||
./venv/bin/...``. These modes of operation might corrupt your operating
|
||||
system and are **not supported** by the Certbot team!
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ manual_ Y N | Helps you obtain a certificate by giving you instruction
|
|||
=========== ==== ==== =============================================================== =============================
|
||||
|
||||
Under the hood, plugins use one of several ACME protocol challenges_ to
|
||||
prove you control a domain. The options are http-01_ (which uses port 80),
|
||||
prove you control a domain. The options are http-01_ (which uses port 80),
|
||||
tls-sni-01_ (port 443) and dns-01_ (requiring configuration of a DNS server on
|
||||
port 53, though that's often not the same machine as your webserver). A few
|
||||
plugins support more than one challenge type, in which case you can choose one
|
||||
|
|
@ -102,7 +102,7 @@ If you're getting a certificate for many domains at once, the plugin
|
|||
needs to know where each domain's files are served from, which could
|
||||
potentially be a separate directory for each domain. When requesting a
|
||||
certificate for multiple domains, each domain will use the most recently
|
||||
specified ``--webroot-path``. So, for instance,
|
||||
specified ``--webroot-path``. So, for instance,
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -332,7 +332,7 @@ Example:
|
|||
|
||||
.. code-block:: none
|
||||
|
||||
certbot --expand -d existing.com example.com,newdomain.com
|
||||
certbot --expand -d existing.com,example.com,newdomain.com
|
||||
|
||||
If you prefer, you can specify the domains individually like this:
|
||||
|
||||
|
|
@ -383,6 +383,12 @@ use the ``revoke`` command to do so. Note that the ``revoke`` command takes the
|
|||
|
||||
certbot revoke --cert-path /etc/letsencrypt/live/CERTNAME/cert.pem
|
||||
|
||||
You can also specify the reason for revoking your certificate by using the ``reason`` flag.
|
||||
Reasons include ``unspecified`` which is the default, as well as ``keycompromise``,
|
||||
``affiliationchanged``, ``superseded``, and ``cessationofoperation``::
|
||||
|
||||
certbot revoke --cert-path /etc/letsencrypt/live/CERTNAME/cert.pem --reason keycompromise
|
||||
|
||||
Additionally, if a certificate
|
||||
is a test certificate obtained via the ``--staging`` or ``--test-cert`` flag, that flag must be passed to the
|
||||
``revoke`` subcommand.
|
||||
|
|
@ -538,8 +544,15 @@ commands into your individual environment.
|
|||
Modifying the Renewal Configuration File
|
||||
----------------------------------------
|
||||
|
||||
When a certificate is issued, by default Certbot creates a renewal configuration file that
|
||||
tracks the options that were selected when Certbot was run. This allows Certbot
|
||||
to use those same options again when it comes time for renewal. These renewal
|
||||
configuration files are located at ``/etc/letsencrypt/renewal/CERTNAME``.
|
||||
|
||||
For advanced certificate management tasks, it is possible to manually modify the certificate's
|
||||
renewal configuration file, located at ``/etc/letsencrypt/renewal/CERTNAME``.
|
||||
renewal configuration file, but this is discouraged since it can easily break Certbot's
|
||||
ability to renew your certificates. If you choose to modify the renewal configuration file
|
||||
we advise you to test its validity with the ``certbot renew --dry-run`` command.
|
||||
|
||||
.. warning:: Modifying any files in ``/etc/letsencrypt`` can damage them so Certbot can no longer properly manage its certificates, and we do not recommend doing so.
|
||||
|
||||
|
|
@ -790,7 +803,12 @@ of Certbot that you would like to run.
|
|||
Configuration file
|
||||
==================
|
||||
|
||||
It is possible to specify configuration file with
|
||||
Certbot accepts a global configuration file that applies its options to all invocations
|
||||
of Certbot. Certificate specific configuration choices should be set in the ``.conf``
|
||||
files that can be found in ``/etc/letsencrypt/renewal``.
|
||||
|
||||
By default no cli.ini file is created, after creating one
|
||||
it is possible to specify the location of this configuration file with
|
||||
``certbot-auto --config cli.ini`` (or shorter ``-c cli.ini``). An
|
||||
example configuration file is shown below:
|
||||
|
||||
|
|
@ -804,6 +822,13 @@ By default, the following locations are searched:
|
|||
``~/.config/letsencrypt/cli.ini`` if ``$XDG_CONFIG_HOME`` is not
|
||||
set).
|
||||
|
||||
Since this configuration file applies to all invocations of certbot it is incorrect
|
||||
to list domains in it. Listing domains in cli.ini may prevent renewal from working.
|
||||
Additionally due to how arguments in cli.ini are parsed, options which wish to
|
||||
not be set should not be listed. Options set to false will instead be read
|
||||
as being set to true by older versions of Certbot, since they have been listed
|
||||
in the config file.
|
||||
|
||||
.. keep it up to date with constants.py
|
||||
|
||||
.. _log-rotation:
|
||||
|
|
@ -823,7 +848,7 @@ changed by passing the desired number to the command line flag
|
|||
Certbot command-line options
|
||||
============================
|
||||
|
||||
Certbot supports a lot of command line options. Here's the full list, from
|
||||
Certbot supports a lot of command line options. Here's the full list, from
|
||||
``certbot --help all``:
|
||||
|
||||
.. literalinclude:: cli-help.txt
|
||||
|
|
|
|||
136
letsencrypt-auto
136
letsencrypt-auto
|
|
@ -28,7 +28,7 @@ if [ -z "$VENV_PATH" ]; then
|
|||
VENV_PATH="$XDG_DATA_HOME/$VENV_NAME"
|
||||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
LE_AUTO_VERSION="0.16.0"
|
||||
LE_AUTO_VERSION="0.17.0"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
|
|
@ -200,6 +200,25 @@ ExperimentalBootstrap() {
|
|||
fi
|
||||
}
|
||||
|
||||
DeprecationBootstrap() {
|
||||
# Arguments: Platform name, bootstrap function name
|
||||
if [ "$DEBUG" = 1 ]; then
|
||||
if [ "$2" != "" ]; then
|
||||
BootstrapMessage $1
|
||||
$2
|
||||
fi
|
||||
else
|
||||
error "WARNING: certbot-auto support for this $1 is DEPRECATED!"
|
||||
error "Please visit certbot.eff.org to learn how to download a version of"
|
||||
error "Certbot that is packaged for your system. While an existing version"
|
||||
error "of certbot-auto may work currently, we have stopped supporting updating"
|
||||
error "system packages for your system. Please switch to a packaged version"
|
||||
error "as soon as possible."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
DeterminePythonVersion() {
|
||||
for LE_PYTHON in "$LE_PYTHON" python2.7 python27 python2 python; do
|
||||
# Break (while keeping the LE_PYTHON value) if found.
|
||||
|
|
@ -630,11 +649,11 @@ Bootstrap() {
|
|||
elif [ -f /etc/manjaro-release ]; then
|
||||
ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon
|
||||
elif [ -f /etc/gentoo-release ]; then
|
||||
ExperimentalBootstrap "Gentoo" BootstrapGentooCommon
|
||||
DeprecationBootstrap "Gentoo" BootstrapGentooCommon
|
||||
elif uname | grep -iq FreeBSD ; then
|
||||
ExperimentalBootstrap "FreeBSD" BootstrapFreeBsd
|
||||
DeprecationBootstrap "FreeBSD" BootstrapFreeBsd
|
||||
elif uname | grep -iq Darwin ; then
|
||||
ExperimentalBootstrap "macOS" BootstrapMac
|
||||
DeprecationBootstrap "macOS" BootstrapMac
|
||||
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
|
||||
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
|
||||
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
|
||||
|
|
@ -751,25 +770,37 @@ ConfigArgParse==0.10.0 \
|
|||
--hash=sha256:3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7
|
||||
configobj==5.0.6 \
|
||||
--hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
|
||||
cryptography==1.9 \
|
||||
--hash=sha256:469a9d3d851038f1eb7d7f77bb08bb4775b41483372be450e25b293fe57bd59e \
|
||||
--hash=sha256:533143321d15c8743f91eec5c5f495c1b5cad9a25de8f6dab01eddd6b416903e \
|
||||
--hash=sha256:2230c186182d773064d06242e0fa604cd718bfff28aa9c5ae73d7e426e98a151 \
|
||||
--hash=sha256:3dc94ed5a26b8553a325767358f505c0a43e0c89df078647f77a4d022ddcdc57 \
|
||||
--hash=sha256:2eb8297b877cb6b56216750fa7017c9f5786bec8afd6a0f1aaace02cbfb6195f \
|
||||
--hash=sha256:025a96e48164106f2082b00f42bf430cf21f09e203e42585a712e420b75cbff0 \
|
||||
--hash=sha256:61eb3534f8ed2415dd708b28919205d523f220e4cd5b8165844edfdd4a649b8e \
|
||||
--hash=sha256:5474fe5ce6b517d3086e0231b6ad88f8978c551c4379f91c3d619c308490f0d7 \
|
||||
--hash=sha256:5ff169869624e23767d70db274f13a9ea4e97c029425a1224aa5e049e84ce2af \
|
||||
--hash=sha256:c26e057a2de13e97e708328d295c5ac4cd3eab4a5c42ce727dd1a53316034b8a \
|
||||
--hash=sha256:7db719432648f14ea33edffc5f75330c595804eac86ca916528b35ce50a8bfd6 \
|
||||
--hash=sha256:ca72537a7064bb80e34b6908e576ffc8e2c2cad29a7168f48d0999df089695c3 \
|
||||
--hash=sha256:2a5e577f5d2093e51486b4ec02b51bb5adb165b98fee99929d5af0813e90b469 \
|
||||
--hash=sha256:9d9da8bac2e31003d092f5ef6981a725c77c4e9a30638436884d61ad39f9a1ee \
|
||||
--hash=sha256:fab8ec6866e384d9827d5dc02a1383e991a6c05c54f818316c4b829e56ca2ba3 \
|
||||
--hash=sha256:365eb804362e581c9a02e7a610b30514f07dd77b2a38aed338eb5192446bbc58 \
|
||||
--hash=sha256:2908f709f02711dbb10561a9f154d2f7d1792385e2341e9708539cc4ecfb8667 \
|
||||
--hash=sha256:5518337022718029e367d982642f3e3523541e098ad671672a90b82474c84882
|
||||
cryptography==2.0.2 \
|
||||
--hash=sha256:187ae17358436d2c760f28c2aeb02fefa3f37647a9c5b6f7f7c3e83cd1c5a972 \
|
||||
--hash=sha256:19e43a13bbf52028dd1e810c803f2ad8880d0692d772f98d42e1eaf34bdee3d6 \
|
||||
--hash=sha256:da9291502cbc87dc0284a20c56876e4d2e68deac61cc43df4aec934e44ca97b1 \
|
||||
--hash=sha256:0954f8813095f581669330e0a2d5e726c33ac7f450c1458fac58bab54595e516 \
|
||||
--hash=sha256:d68b0cc40a8432ed3fc84876c519de704d6001800ec22b136e75ae841910c45b \
|
||||
--hash=sha256:2f8ad9580ab4da645cfea52a91d2da99a49a1e76616d8be68441a986fad652b0 \
|
||||
--hash=sha256:cc00b4511294f5f6b65c4e77a1a9c62f52490a63d2c120f3872176b40a82351e \
|
||||
--hash=sha256:cf896020f6a9f095a547b3d672c8db1ef2ed71fca11250731fa1d4a4cb8b1590 \
|
||||
--hash=sha256:e0fdb8322206fa02aa38f71519ff75dce2eb481b7e1110e2936795cb376bb6ee \
|
||||
--hash=sha256:277538466657ca5d6637f80be100242f9831d75138b788d718edd3aab34621f8 \
|
||||
--hash=sha256:2c77eb0560f54ce654ab82d6b2a64327a71ee969b29022bf9746ca311c9f5069 \
|
||||
--hash=sha256:755a7853b679e79d0a799351c092a9b0271f95ff54c8dd8823d8b527a2926a86 \
|
||||
--hash=sha256:77197a2d525e761cdd4c771180b4bd0d80703654c6385e4311cbbbe2beb56fa1 \
|
||||
--hash=sha256:eb8bb79d0ab00c931c8333b745f06fec481a51c52d70acd4ee95d6093ba5c386 \
|
||||
--hash=sha256:131f61de82ef28f3e20beb4bfc24f9692d28cecfd704e20e6c7f070f7793013a \
|
||||
--hash=sha256:ac35435974b2e27cd4520f29c191d7da36f4189aa3264e52c4c6c6d089ab6142 \
|
||||
--hash=sha256:04b6ea99daa2a8460728794213d76d45ad58ea247dc7e7ff148d7dd726e87863 \
|
||||
--hash=sha256:2b9442f8b4c3d575f6cc3db0e856034e0f5a9d55ecd636f52d8c496795b26952 \
|
||||
--hash=sha256:b3d3b3ecba1fe1bdb6f180770a137f877c8f07571f7b2934bb269475bcf0e5e8 \
|
||||
--hash=sha256:670a58c0d75cb0e78e73dd003bd96d4440bbb1f2bc041dcf7b81767ca4fb0ce9 \
|
||||
--hash=sha256:5af84d23bdb86b5e90aca263df1424b43f1748480bfcde3ac2a3cbe622612468 \
|
||||
--hash=sha256:ba22e8eefabdd7aca37d0c0c00d2274000d2cebb5cce9e5a710cb55bf8797b31 \
|
||||
--hash=sha256:b798b22fa7e92b439547323b8b719d217f1e1b7677585cfeeedf3b55c70bb7fb \
|
||||
--hash=sha256:59cff28af8cce96cb7e94a459726e1d88f6f5fa75097f9dcbebd99118d64ea4c \
|
||||
--hash=sha256:fe859e445abc9ba9e97950ddafb904e23234c4ecb76b0fae6c86e80592ce464a \
|
||||
--hash=sha256:655f3c474067f1e277430f23cc0549f0b1dc99b82aec6e53f80b9b2db7f76f11 \
|
||||
--hash=sha256:0ebc2be053c9a03a2f3e20a466e87bf12a51586b3c79bd2a22171b073a805346 \
|
||||
--hash=sha256:01e6e60654df64cca53733cda39446d67100c819c181d403afb120e0d2a71e1b \
|
||||
--hash=sha256:d46f4e5d455cb5563685c52ef212696f0a6cc1ea627603218eabbd8a095291d8 \
|
||||
--hash=sha256:3780b2663ee7ebb37cb83263326e3cd7f8b2ea439c448539d4b87de12c8d06ab
|
||||
enum34==1.1.2 \
|
||||
--hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \
|
||||
--hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501
|
||||
|
|
@ -876,18 +907,18 @@ letsencrypt==0.7.0 \
|
|||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==0.16.0 \
|
||||
--hash=sha256:e1cc2479f4f149a7128b67192c3f5f6c111b6b9ddcac421ebee8ac5030d5b09b \
|
||||
--hash=sha256:795801fd6b06b32060e364ac045312e6b26c6272d5ca32878277e5a2afdee186
|
||||
acme==0.16.0 \
|
||||
--hash=sha256:31592a744f7a6e7cbb4c5daf2deebc9af6b03997d6f80e5becc203ab8694edcf \
|
||||
--hash=sha256:538b69134cc50bdcdcc081b844c85158509022c61d7abc1f44216beeb95de9cd
|
||||
certbot-apache==0.16.0 \
|
||||
--hash=sha256:337f84f391c7d7c31d84376e7a8c882ac119112a4aabceadd1a7de6a2f01ca06 \
|
||||
--hash=sha256:f1f37b56e1ceb0a28ccf51d54ca34444e6a708448845ef25372e223b9a82c4d4
|
||||
certbot-nginx==0.16.0 \
|
||||
--hash=sha256:1d57428202f8e7abdd99c3ddbcf374aad5f69c4262fe8dae53d2016e4ae04ded \
|
||||
--hash=sha256:77711655514d707ddf728195f00b2f6cdd1ad9db52440276b4a67664479c6954
|
||||
certbot==0.17.0 \
|
||||
--hash=sha256:64c25c7123357feffded6408660bc6f5c7d493dd635ae172081d21473075a86a \
|
||||
--hash=sha256:43f5b26c3f314d14babf79a3bdf3522e4fc9eef867a0681c426f113c650a669c
|
||||
acme==0.17.0 \
|
||||
--hash=sha256:501710171633af13fc52aa61d0277a6fe335f7477db5810e72239aaf4f3a09e7 \
|
||||
--hash=sha256:3ccbe4aaeb98c77b98ee4093b4e4adb76a1a24cbdfec0130c489c206f1d9b66e
|
||||
certbot-apache==0.17.0 \
|
||||
--hash=sha256:17a7e8d7526d838610e68b96cf052af17c4055655b76b06d1cbc74857d90a216 \
|
||||
--hash=sha256:29b9e7bc5eaaff6dc4bce8398e35eeacdf346126aad68cac3d41bb87df20a6b9
|
||||
certbot-nginx==0.17.0 \
|
||||
--hash=sha256:980c9a33a79ab839a089a0085ff0c5414f01f47b6db26ed342df25916658cec9 \
|
||||
--hash=sha256:e573f8b4283172755c07b9cca8a8da7ef2d31b4df763881394b5339b2d42994a
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
|
@ -915,6 +946,7 @@ anything goes wrong, it will exit with a non-zero status code.
|
|||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
from __future__ import print_function
|
||||
from distutils.version import StrictVersion
|
||||
from hashlib import sha256
|
||||
from os.path import join
|
||||
from pipes import quote
|
||||
|
|
@ -949,12 +981,14 @@ except ImportError:
|
|||
from urllib.parse import urlparse # 3.4
|
||||
|
||||
|
||||
__version__ = 1, 1, 1
|
||||
__version__ = 1, 3, 0
|
||||
PIP_VERSION = '9.0.1'
|
||||
|
||||
|
||||
# wheel has a conditional dependency on argparse:
|
||||
maybe_argparse = (
|
||||
[('https://pypi.python.org/packages/source/a/argparse/'
|
||||
[('https://pypi.python.org/packages/18/dd/'
|
||||
'e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/'
|
||||
'argparse-1.4.0.tar.gz',
|
||||
'62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')]
|
||||
if version_info < (2, 7, 0) else [])
|
||||
|
|
@ -962,13 +996,19 @@ maybe_argparse = (
|
|||
|
||||
PACKAGES = maybe_argparse + [
|
||||
# Pip has no dependencies, as it vendors everything:
|
||||
('https://pypi.python.org/packages/source/p/pip/pip-8.0.3.tar.gz',
|
||||
'30f98b66f3fe1069c529a491597d34a1c224a68640c82caf2ade5f88aa1405e8'),
|
||||
('https://pypi.python.org/packages/11/b6/'
|
||||
'abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/'
|
||||
'pip-{0}.tar.gz'
|
||||
.format(PIP_VERSION),
|
||||
'09f243e1a7b461f654c26a725fa373211bb7ff17a9300058b205c61658ca940d'),
|
||||
# This version of setuptools has only optional dependencies:
|
||||
('https://pypi.python.org/packages/source/s/setuptools/'
|
||||
('https://pypi.python.org/packages/69/65/'
|
||||
'4c544cde88d4d876cdf5cbc5f3f15d02646477756d89547e9a7ecd6afa76/'
|
||||
'setuptools-20.2.2.tar.gz',
|
||||
'24fcfc15364a9fe09a220f37d2dcedc849795e3de3e4b393ee988e66a9cbd85a'),
|
||||
('https://pypi.python.org/packages/source/w/wheel/wheel-0.29.0.tar.gz',
|
||||
('https://pypi.python.org/packages/c9/1d/'
|
||||
'bd19e691fd4cfe908c76c429fe6e4436c9e83583c4414b54f6c85471954a/'
|
||||
'wheel-0.29.0.tar.gz',
|
||||
'1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648')
|
||||
]
|
||||
|
||||
|
|
@ -1018,11 +1058,21 @@ def hashed_download(url, temp, digest):
|
|||
|
||||
|
||||
def main():
|
||||
pip_version = StrictVersion(check_output(['pip', '--version'])
|
||||
.decode('utf-8').split()[1])
|
||||
min_pip_version = StrictVersion(PIP_VERSION)
|
||||
if pip_version >= min_pip_version:
|
||||
return 0
|
||||
has_pip_cache = pip_version >= StrictVersion('6.0')
|
||||
|
||||
temp = mkdtemp(prefix='pipstrap-')
|
||||
try:
|
||||
downloads = [hashed_download(url, temp, digest)
|
||||
for url, digest in PACKAGES]
|
||||
check_output('pip install --no-index --no-deps -U ' +
|
||||
# Disable cache since we're not using it and it otherwise
|
||||
# sometimes throws permission warnings:
|
||||
('--no-cache-dir ' if has_pip_cache else '') +
|
||||
' '.join(quote(d) for d in downloads),
|
||||
shell=True)
|
||||
except HashError as exc:
|
||||
|
|
@ -1045,9 +1095,9 @@ UNLIKELY_EOF
|
|||
PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py"
|
||||
set +e
|
||||
if [ "$VERBOSE" = 1 ]; then
|
||||
"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt"
|
||||
"$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt"
|
||||
else
|
||||
PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1`
|
||||
PIP_OUT=`"$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1`
|
||||
fi
|
||||
PIP_STATUS=$?
|
||||
set -e
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v2
|
||||
|
||||
iQEcBAABCAAGBQJZXV5PAAoJEE0XyZXNl3Xy3IgH/1OiY21IcAGx13jW32KNIsf9
|
||||
/vqjR/fyPbraSzYDldCVIQxsaVA6oh2kNZgiB11OpPT20/WsDq1+Ymj+dMjonJfm
|
||||
w3wjx5AnfR/YThQwNXUJ83XnPCA78CtYiXus9gyqk+10WpNXUkbdGOwM4eYOtb3o
|
||||
fNjJXkA00pATIYXks6qV0WJVEDNYuHDfkDfxukVgU7HzjfayLQjo4Zbs7Qnp7oH9
|
||||
+Lizc11nTliUUo3hHyLziJsCfC+Irso5Q/fHM9rn9DS360PcW0uNjWeLQk0U1w1l
|
||||
tuuObOsDi/7Rejk4uDu6qDVemdEoG1btCrZgzOvzi3NstWigrL76cZuoz0gaGu4=
|
||||
=mN1c
|
||||
iQEcBAABCAAGBQJZgRYdAAoJEE0XyZXNl3XyNskIAMh/M3tV8PTieSrMr3uzLua8
|
||||
R+tQJV31WlraoKGQAkZ9Ak+nEhJy0bOi3QAeOmEnS15sBM6ruD+UCfwUDrZxolfW
|
||||
5Fnue2ocym+MhfDNKoerQNAmaaHY8sutoR+RNTegFyfyr92zMDZVzPm/DFAAHbK+
|
||||
eJltSx2Jleaig4V/RcKpkCwHErjQxn6Tn4jHlafAdNL28tEIGXcExpRj4raw3X1L
|
||||
SoTq/yJiWe+M7t+1iBRVEMZHY1b47PbTo1ipKF/ZZ3Hrz5JKRhAKcA8diHlWp+1I
|
||||
ujAfU4uu0hR+C3wcpeJ1i2YdS4S9y6uMGyIWU5toJfYdolTSGRZ2lPB+x5Um9pw=
|
||||
=/7P7
|
||||
-----END PGP SIGNATURE-----
|
||||
|
|
|
|||
|
|
@ -23,12 +23,15 @@ fi
|
|||
if [ -z "$XDG_DATA_HOME" ]; then
|
||||
XDG_DATA_HOME=~/.local/share
|
||||
fi
|
||||
VENV_NAME="letsencrypt"
|
||||
if [ -z "$VENV_PATH" ]; then
|
||||
VENV_PATH="$XDG_DATA_HOME/$VENV_NAME"
|
||||
# We export these values so they are preserved properly if this script is
|
||||
# rerun with sudo/su where $HOME/$XDG_DATA_HOME may have a different value.
|
||||
export OLD_VENV_PATH="$XDG_DATA_HOME/letsencrypt"
|
||||
export VENV_PATH="/opt/eff.org/certbot/venv"
|
||||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
LE_AUTO_VERSION="0.17.0.dev0"
|
||||
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
|
||||
LE_AUTO_VERSION="0.18.0.dev0"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
|
|
@ -49,6 +52,7 @@ Help for certbot itself cannot be provided until it is installed.
|
|||
implies --non-interactive
|
||||
|
||||
All arguments are accepted and forwarded to the Certbot client when run."
|
||||
export CERTBOT_AUTO="$0"
|
||||
|
||||
for arg in "$@" ; do
|
||||
case "$arg" in
|
||||
|
|
@ -77,7 +81,7 @@ for arg in "$@" ; do
|
|||
h)
|
||||
HELP=1;;
|
||||
n)
|
||||
ASSUME_YES=1;;
|
||||
NONINTERACTIVE=1;;
|
||||
q)
|
||||
QUIET=1;;
|
||||
v)
|
||||
|
|
@ -93,8 +97,8 @@ if [ $BASENAME = "letsencrypt-auto" ]; then
|
|||
HELP=0
|
||||
fi
|
||||
|
||||
# Set ASSUME_YES to 1 if QUIET (i.e. --quiet implies --non-interactive)
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
# Set ASSUME_YES to 1 if QUIET or NONINTERACTIVE
|
||||
if [ "$QUIET" = 1 -o "$NONINTERACTIVE" = 1 ]; then
|
||||
ASSUME_YES=1
|
||||
fi
|
||||
|
||||
|
|
@ -119,16 +123,18 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# certbot-auto needs root access to bootstrap OS dependencies, and
|
||||
# certbot itself needs root access for almost all modes of operation
|
||||
# The "normal" case is that sudo is used for the steps that need root, but
|
||||
# this script *can* be run as root (not recommended), or fall back to using
|
||||
# `su`. Auto-detection can be overridden by explicitly setting the
|
||||
# environment variable LE_AUTO_SUDO to 'sudo', 'sudo_su' or '' as used below.
|
||||
# Certbot itself needs root access for almost all modes of operation.
|
||||
# certbot-auto needs root access to bootstrap OS dependencies and install
|
||||
# Certbot at a protected path so it can be safely run as root. To accomplish
|
||||
# this, this script will attempt to run itself as root if it doesn't have the
|
||||
# necessary privileges by using `sudo` or falling back to `su` if it is not
|
||||
# available. The mechanism used to obtain root access can be set explicitly by
|
||||
# setting the environment variable LE_AUTO_SUDO to 'sudo', 'su', 'su_sudo',
|
||||
# 'SuSudo', or '' as used below.
|
||||
|
||||
# Because the parameters in `su -c` has to be a string,
|
||||
# we need to properly escape it.
|
||||
su_sudo() {
|
||||
SuSudo() {
|
||||
args=""
|
||||
# This `while` loop iterates over all parameters given to this function.
|
||||
# For each parameter, all `'` will be replace by `'"'"'`, and the escaped string
|
||||
|
|
@ -147,34 +153,47 @@ su_sudo() {
|
|||
su root -c "$args"
|
||||
}
|
||||
|
||||
SUDO_ENV=""
|
||||
export CERTBOT_AUTO="$0"
|
||||
if [ -n "${LE_AUTO_SUDO+x}" ]; then
|
||||
case "$LE_AUTO_SUDO" in
|
||||
su_sudo|su)
|
||||
SUDO=su_sudo
|
||||
;;
|
||||
sudo)
|
||||
SUDO=sudo
|
||||
SUDO_ENV="CERTBOT_AUTO=$0"
|
||||
;;
|
||||
'') ;; # Nothing to do for plain root method.
|
||||
*)
|
||||
error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
exit 1
|
||||
esac
|
||||
say "Using preset root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
else
|
||||
if test "`id -u`" -ne "0" ; then
|
||||
if $EXISTS sudo 1>/dev/null 2>&1; then
|
||||
SUDO=sudo
|
||||
SUDO_ENV="CERTBOT_AUTO=$0"
|
||||
else
|
||||
say \"sudo\" is not available, will use \"su\" for installation steps...
|
||||
SUDO=su_sudo
|
||||
fi
|
||||
# Sets the environment variable SUDO to be the name of the program or function
|
||||
# to call to get root access. If this script already has root privleges, SUDO
|
||||
# is set to an empty string. The value in SUDO should be run with the command
|
||||
# to called with root privileges as arguments.
|
||||
SetRootAuthMechanism() {
|
||||
SUDO=""
|
||||
if [ -n "${LE_AUTO_SUDO+x}" ]; then
|
||||
case "$LE_AUTO_SUDO" in
|
||||
SuSudo|su_sudo|su)
|
||||
SUDO=SuSudo
|
||||
;;
|
||||
sudo)
|
||||
SUDO="sudo -E"
|
||||
;;
|
||||
'') ;; # Nothing to do for plain root method.
|
||||
*)
|
||||
error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
exit 1
|
||||
esac
|
||||
say "Using preset root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
else
|
||||
SUDO=
|
||||
if test "`id -u`" -ne "0" ; then
|
||||
if $EXISTS sudo 1>/dev/null 2>&1; then
|
||||
SUDO="sudo -E"
|
||||
else
|
||||
say \"sudo\" is not available, will use \"su\" for installation steps...
|
||||
SUDO=SuSudo
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$1" = "--cb-auto-has-root" ]; then
|
||||
shift 1
|
||||
elif [ "$1" != "--le-auto-phase2" ]; then
|
||||
# if $1 is --le-auto-phase2, we've executed this branch before
|
||||
SetRootAuthMechanism
|
||||
if [ -n "$SUDO" ]; then
|
||||
echo "Requesting to rerun $0 with root privileges..."
|
||||
$SUDO "$0" --cb-auto-has-root "$@"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
@ -238,6 +257,10 @@ DeterminePythonVersion() {
|
|||
fi
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapDebCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_DEB_COMMON_VERSION=1
|
||||
|
||||
BootstrapDebCommon() {
|
||||
# Current version tested with:
|
||||
#
|
||||
|
|
@ -261,7 +284,7 @@ BootstrapDebCommon() {
|
|||
QUIET_FLAG='-qq'
|
||||
fi
|
||||
|
||||
$SUDO apt-get $QUIET_FLAG update || error apt-get update hit problems but continuing anyway...
|
||||
apt-get $QUIET_FLAG update || error apt-get update hit problems but continuing anyway...
|
||||
|
||||
# virtualenv binary can be found in different packages depending on
|
||||
# distro version (#346)
|
||||
|
|
@ -311,13 +334,13 @@ BootstrapDebCommon() {
|
|||
esac
|
||||
fi
|
||||
if [ "$add_backports" = 1 ]; then
|
||||
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
|
||||
$SUDO apt-get $QUIET_FLAG update
|
||||
sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
|
||||
apt-get $QUIET_FLAG update
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ "$add_backports" != 0 ]; then
|
||||
$SUDO apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
|
||||
apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
|
||||
augeas_pkg=
|
||||
fi
|
||||
}
|
||||
|
|
@ -336,7 +359,7 @@ BootstrapDebCommon() {
|
|||
# XXX add a case for ubuntu PPAs
|
||||
fi
|
||||
|
||||
$SUDO apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends \
|
||||
apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends \
|
||||
python \
|
||||
python-dev \
|
||||
$virtualenv \
|
||||
|
|
@ -354,6 +377,10 @@ BootstrapDebCommon() {
|
|||
fi
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapRpmCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_RPM_COMMON_VERSION=1
|
||||
|
||||
BootstrapRpmCommon() {
|
||||
# Tested with:
|
||||
# - Fedora 20, 21, 22, 23 (x64)
|
||||
|
|
@ -380,9 +407,9 @@ BootstrapRpmCommon() {
|
|||
QUIET_FLAG='--quiet'
|
||||
fi
|
||||
|
||||
if ! $SUDO $tool list *virtualenv >/dev/null 2>&1; then
|
||||
if ! $tool list *virtualenv >/dev/null 2>&1; then
|
||||
echo "To use Certbot, packages from the EPEL repository need to be installed."
|
||||
if ! $SUDO $tool list epel-release >/dev/null 2>&1; then
|
||||
if ! $tool list epel-release >/dev/null 2>&1; then
|
||||
error "Enable the EPEL repository and try running Certbot again."
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -394,7 +421,7 @@ BootstrapRpmCommon() {
|
|||
/bin/echo -e "\e[0K\rEnabling the EPEL repository in 1 seconds..."
|
||||
sleep 1s
|
||||
fi
|
||||
if ! $SUDO $tool install $yes_flag $QUIET_FLAG epel-release; then
|
||||
if ! $tool install $yes_flag $QUIET_FLAG epel-release; then
|
||||
error "Could not enable EPEL. Aborting bootstrap!"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -410,9 +437,8 @@ BootstrapRpmCommon() {
|
|||
ca-certificates
|
||||
"
|
||||
|
||||
# Some distros and older versions of current distros use a "python27"
|
||||
# instead of "python" naming convention. Try both conventions.
|
||||
if $SUDO $tool list python >/dev/null 2>&1; then
|
||||
# Most RPM distros use the "python" or "python-" naming convention. Let's try that first.
|
||||
if $tool list python >/dev/null 2>&1; then
|
||||
pkgs="$pkgs
|
||||
python
|
||||
python-devel
|
||||
|
|
@ -420,6 +446,20 @@ BootstrapRpmCommon() {
|
|||
python-tools
|
||||
python-pip
|
||||
"
|
||||
# Fedora 26 starts to use the prefix python2 for python2 based packages.
|
||||
# this elseif is theoretically for any Fedora over version 26:
|
||||
elif $tool list python2 >/dev/null 2>&1; then
|
||||
pkgs="$pkgs
|
||||
python2
|
||||
python2-libs
|
||||
python2-setuptools
|
||||
python2-devel
|
||||
python2-virtualenv
|
||||
python2-tools
|
||||
python2-pip
|
||||
"
|
||||
# Some distros and older versions of current distros use a "python27"
|
||||
# instead of the "python" or "python-" naming convention.
|
||||
else
|
||||
pkgs="$pkgs
|
||||
python27
|
||||
|
|
@ -430,18 +470,22 @@ BootstrapRpmCommon() {
|
|||
"
|
||||
fi
|
||||
|
||||
if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then
|
||||
if $tool list installed "httpd" >/dev/null 2>&1; then
|
||||
pkgs="$pkgs
|
||||
mod_ssl
|
||||
"
|
||||
fi
|
||||
|
||||
if ! $SUDO $tool install $yes_flag $QUIET_FLAG $pkgs; then
|
||||
if ! $tool install $yes_flag $QUIET_FLAG $pkgs; then
|
||||
error "Could not install OS dependencies. Aborting bootstrap!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapSuseCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_SUSE_COMMON_VERSION=1
|
||||
|
||||
BootstrapSuseCommon() {
|
||||
# SLE12 don't have python-virtualenv
|
||||
|
||||
|
|
@ -454,7 +498,7 @@ BootstrapSuseCommon() {
|
|||
QUIET_FLAG='-qq'
|
||||
fi
|
||||
|
||||
$SUDO zypper $QUIET_FLAG $zypper_flags in $install_flags \
|
||||
zypper $QUIET_FLAG $zypper_flags in $install_flags \
|
||||
python \
|
||||
python-devel \
|
||||
python-virtualenv \
|
||||
|
|
@ -465,6 +509,10 @@ BootstrapSuseCommon() {
|
|||
ca-certificates
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapArchCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_ARCH_COMMON_VERSION=1
|
||||
|
||||
BootstrapArchCommon() {
|
||||
# Tested with:
|
||||
# - ArchLinux (x86_64)
|
||||
|
|
@ -485,21 +533,25 @@ BootstrapArchCommon() {
|
|||
"
|
||||
|
||||
# pacman -T exits with 127 if there are missing dependencies
|
||||
missing=$($SUDO pacman -T $deps) || true
|
||||
missing=$(pacman -T $deps) || true
|
||||
|
||||
if [ "$ASSUME_YES" = 1 ]; then
|
||||
noconfirm="--noconfirm"
|
||||
fi
|
||||
|
||||
if [ "$missing" ]; then
|
||||
if [ "$QUIET" = 1]; then
|
||||
$SUDO pacman -S --needed $missing $noconfirm > /dev/null
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
pacman -S --needed $missing $noconfirm > /dev/null
|
||||
else
|
||||
$SUDO pacman -S --needed $missing $noconfirm
|
||||
pacman -S --needed $missing $noconfirm
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapGentooCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_GENTOO_COMMON_VERSION=1
|
||||
|
||||
BootstrapGentooCommon() {
|
||||
PACKAGES="
|
||||
dev-lang/python:2.7
|
||||
|
|
@ -517,29 +569,37 @@ BootstrapGentooCommon() {
|
|||
|
||||
case "$PACKAGE_MANAGER" in
|
||||
(paludis)
|
||||
$SUDO cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
|
||||
cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
|
||||
;;
|
||||
(pkgcore)
|
||||
$SUDO pmerge --noreplace --oneshot $ASK_OPTION $PACKAGES
|
||||
pmerge --noreplace --oneshot $ASK_OPTION $PACKAGES
|
||||
;;
|
||||
(portage|*)
|
||||
$SUDO emerge --noreplace --oneshot $ASK_OPTION $PACKAGES
|
||||
emerge --noreplace --oneshot $ASK_OPTION $PACKAGES
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapFreeBsd below, this version number
|
||||
# must be increased.
|
||||
BOOTSTRAP_FREEBSD_VERSION=1
|
||||
|
||||
BootstrapFreeBsd() {
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
QUIET_FLAG="--quiet"
|
||||
fi
|
||||
|
||||
$SUDO pkg install -Ay $QUIET_FLAG \
|
||||
pkg install -Ay $QUIET_FLAG \
|
||||
python \
|
||||
py27-virtualenv \
|
||||
augeas \
|
||||
libffi
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapMac below, this version number must
|
||||
# be increased.
|
||||
BOOTSTRAP_MAC_VERSION=1
|
||||
|
||||
BootstrapMac() {
|
||||
if hash brew 2>/dev/null; then
|
||||
say "Using Homebrew to install dependencies..."
|
||||
|
|
@ -548,7 +608,7 @@ BootstrapMac() {
|
|||
elif hash port 2>/dev/null; then
|
||||
say "Using MacPorts to install dependencies..."
|
||||
pkgman=port
|
||||
pkgcmd="$SUDO port install"
|
||||
pkgcmd="port install"
|
||||
else
|
||||
say "No Homebrew/MacPorts; installing Homebrew..."
|
||||
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
|
|
@ -568,8 +628,8 @@ BootstrapMac() {
|
|||
# Workaround for _dlopen not finding augeas on macOS
|
||||
if [ "$pkgman" = "port" ] && ! [ -e "/usr/local/lib/libaugeas.dylib" ] && [ -e "/opt/local/lib/libaugeas.dylib" ]; then
|
||||
say "Applying augeas workaround"
|
||||
$SUDO mkdir -p /usr/local/lib/
|
||||
$SUDO ln -s /opt/local/lib/libaugeas.dylib /usr/local/lib/
|
||||
mkdir -p /usr/local/lib/
|
||||
ln -s /opt/local/lib/libaugeas.dylib /usr/local/lib/
|
||||
fi
|
||||
|
||||
if ! hash pip 2>/dev/null; then
|
||||
|
|
@ -585,17 +645,25 @@ BootstrapMac() {
|
|||
fi
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapSmartOS below, this version number
|
||||
# must be increased.
|
||||
BOOTSTRAP_SMARTOS_VERSION=1
|
||||
|
||||
BootstrapSmartOS() {
|
||||
pkgin update
|
||||
pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv'
|
||||
}
|
||||
|
||||
# If new packages are installed by BootstrapMageiaCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_MAGEIA_COMMON_VERSION=1
|
||||
|
||||
BootstrapMageiaCommon() {
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
QUIET_FLAG='--quiet'
|
||||
fi
|
||||
|
||||
if ! $SUDO urpmi --force $QUIET_FLAG \
|
||||
if ! urpmi --force $QUIET_FLAG \
|
||||
python \
|
||||
libpython-devel \
|
||||
python-virtualenv
|
||||
|
|
@ -604,7 +672,7 @@ BootstrapMageiaCommon() {
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if ! $SUDO urpmi --force $QUIET_FLAG \
|
||||
if ! urpmi --force $QUIET_FLAG \
|
||||
git \
|
||||
gcc \
|
||||
python-augeas \
|
||||
|
|
@ -618,23 +686,41 @@ BootstrapMageiaCommon() {
|
|||
}
|
||||
|
||||
|
||||
# Install required OS packages:
|
||||
Bootstrap() {
|
||||
if [ "$NO_BOOTSTRAP" = 1 ]; then
|
||||
return
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
# Set Bootstrap to the function that installs OS dependencies on this system
|
||||
# and BOOTSTRAP_VERSION to the unique identifier for the current version of
|
||||
# that function. If Bootstrap is set to a function that doesn't install any
|
||||
# packages (either because --no-bootstrap was included on the command line or
|
||||
# we don't know how to bootstrap on this system), BOOTSTRAP_VERSION is not set.
|
||||
if [ "$NO_BOOTSTRAP" = 1 ]; then
|
||||
Bootstrap() {
|
||||
:
|
||||
}
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
Bootstrap() {
|
||||
BootstrapMessage "Debian-based OSes"
|
||||
BootstrapDebCommon
|
||||
elif [ -f /etc/mageia-release ]; then
|
||||
# Mageia has both /etc/mageia-release and /etc/redhat-release
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapDebCommon $BOOTSTRAP_DEB_COMMON_VERSION"
|
||||
elif [ -f /etc/mageia-release ]; then
|
||||
# Mageia has both /etc/mageia-release and /etc/redhat-release
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Mageia" BootstrapMageiaCommon
|
||||
elif [ -f /etc/redhat-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapMageiaCommon $BOOTSTRAP_MAGEIA_COMMON_VERSION"
|
||||
elif [ -f /etc/redhat-release ]; then
|
||||
Bootstrap() {
|
||||
BootstrapMessage "RedHat-based OSes"
|
||||
BootstrapRpmCommon
|
||||
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
|
||||
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
|
||||
Bootstrap() {
|
||||
BootstrapMessage "openSUSE-based OSes"
|
||||
BootstrapSuseCommon
|
||||
elif [ -f /etc/arch-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapSuseCommon $BOOTSTRAP_SUSE_COMMON_VERSION"
|
||||
elif [ -f /etc/arch-release ]; then
|
||||
Bootstrap() {
|
||||
if [ "$DEBUG" = 1 ]; then
|
||||
BootstrapMessage "Archlinux"
|
||||
BootstrapArchCommon
|
||||
|
|
@ -646,25 +732,76 @@ Bootstrap() {
|
|||
error "--debug flag."
|
||||
exit 1
|
||||
fi
|
||||
elif [ -f /etc/manjaro-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapArchCommon $BOOTSTRAP_ARCH_COMMON_VERSION"
|
||||
elif [ -f /etc/manjaro-release ]; then
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon
|
||||
elif [ -f /etc/gentoo-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapArchCommon $BOOTSTRAP_ARCH_COMMON_VERSION"
|
||||
elif [ -f /etc/gentoo-release ]; then
|
||||
Bootstrap() {
|
||||
DeprecationBootstrap "Gentoo" BootstrapGentooCommon
|
||||
elif uname | grep -iq FreeBSD ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapGentooCommon $BOOTSTRAP_GENTOO_COMMON_VERSION"
|
||||
elif uname | grep -iq FreeBSD ; then
|
||||
Bootstrap() {
|
||||
DeprecationBootstrap "FreeBSD" BootstrapFreeBsd
|
||||
elif uname | grep -iq Darwin ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapFreeBsd $BOOTSTRAP_FREEBSD_VERSION"
|
||||
elif uname | grep -iq Darwin ; then
|
||||
Bootstrap() {
|
||||
DeprecationBootstrap "macOS" BootstrapMac
|
||||
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapMac $BOOTSTRAP_MAC_VERSION"
|
||||
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
|
||||
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
|
||||
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Joyent SmartOS Zone" BootstrapSmartOS
|
||||
else
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapSmartOS $BOOTSTRAP_SMARTOS_VERSION"
|
||||
else
|
||||
Bootstrap() {
|
||||
error "Sorry, I don't know how to bootstrap Certbot on your operating system!"
|
||||
error
|
||||
error "You will need to install OS dependencies, configure virtualenv, and run pip install manually."
|
||||
error "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites"
|
||||
error "for more info."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Sets PREV_BOOTSTRAP_VERSION to the identifier for the bootstrap script used
|
||||
# to install OS dependencies on this system. PREV_BOOTSTRAP_VERSION isn't set
|
||||
# if it is unknown how OS dependencies were installed on this system.
|
||||
SetPrevBootstrapVersion() {
|
||||
if [ -f $BOOTSTRAP_VERSION_PATH ]; then
|
||||
PREV_BOOTSTRAP_VERSION=$(cat "$BOOTSTRAP_VERSION_PATH")
|
||||
# The list below only contains bootstrap version strings that existed before
|
||||
# we started writing them to disk.
|
||||
#
|
||||
# DO NOT MODIFY THIS LIST UNLESS YOU KNOW WHAT YOU'RE DOING!
|
||||
elif grep -Fqx "$BOOTSTRAP_VERSION" << "UNLIKELY_EOF"
|
||||
BootstrapDebCommon 1
|
||||
BootstrapMageiaCommon 1
|
||||
BootstrapRpmCommon 1
|
||||
BootstrapSuseCommon 1
|
||||
BootstrapArchCommon 1
|
||||
BootstrapGentooCommon 1
|
||||
BootstrapFreeBsd 1
|
||||
BootstrapMac 1
|
||||
BootstrapSmartOS 1
|
||||
UNLIKELY_EOF
|
||||
then
|
||||
# If there's no bootstrap version saved to disk, but the currently selected
|
||||
# bootstrap script is from before we started saving the version number,
|
||||
# return the currently selected version to prevent us from rebootstrapping
|
||||
# unnecessarily.
|
||||
PREV_BOOTSTRAP_VERSION="$BOOTSTRAP_VERSION"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -678,18 +815,39 @@ if [ "$1" = "--le-auto-phase2" ]; then
|
|||
# Phase 2: Create venv, install LE, and run.
|
||||
|
||||
shift 1 # the --le-auto-phase2 arg
|
||||
if [ -f "$VENV_BIN/letsencrypt" ]; then
|
||||
# --version output ran through grep due to python-cryptography DeprecationWarnings
|
||||
# grep for both certbot and letsencrypt until certbot and shim packages have been released
|
||||
INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2)
|
||||
if [ -z "$INSTALLED_VERSION" ]; then
|
||||
error "Error: couldn't get currently installed version for $VENV_BIN/letsencrypt: " 1>&2
|
||||
"$VENV_BIN/letsencrypt" --version
|
||||
exit 1
|
||||
SetPrevBootstrapVersion
|
||||
|
||||
INSTALLED_VERSION="none"
|
||||
if [ -d "$VENV_PATH" ]; then
|
||||
# If the selected Bootstrap function isn't a noop and it differs from the
|
||||
# previously used version
|
||||
if [ -n "$BOOTSTRAP_VERSION" -a "$BOOTSTRAP_VERSION" != "$PREV_BOOTSTRAP_VERSION" ]; then
|
||||
# if non-interactive mode or stdin and stdout are connected to a terminal
|
||||
if [ \( "$NONINTERACTIVE" = 1 \) -o \( \( -t 0 \) -a \( -t 1 \) \) ]; then
|
||||
rm -rf "$VENV_PATH"
|
||||
"$0" "$@"
|
||||
exit 0
|
||||
else
|
||||
error "Skipping upgrade because new OS dependencies may need to be installed."
|
||||
error
|
||||
error "To upgrade to a newer version, please run this script again manually so you can"
|
||||
error "approve changes or with --non-interactive on the command line to automatically"
|
||||
error "install any required packages."
|
||||
# Set INSTALLED_VERSION to be the same so we don't update the venv
|
||||
INSTALLED_VERSION="$LE_AUTO_VERSION"
|
||||
fi
|
||||
elif [ -f "$VENV_BIN/letsencrypt" ]; then
|
||||
# --version output ran through grep due to python-cryptography DeprecationWarnings
|
||||
# grep for both certbot and letsencrypt until certbot and shim packages have been released
|
||||
INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2)
|
||||
if [ -z "$INSTALLED_VERSION" ]; then
|
||||
error "Error: couldn't get currently installed version for $VENV_BIN/letsencrypt: " 1>&2
|
||||
"$VENV_BIN/letsencrypt" --version
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
INSTALLED_VERSION="none"
|
||||
fi
|
||||
|
||||
if [ "$LE_AUTO_VERSION" != "$INSTALLED_VERSION" ]; then
|
||||
say "Creating virtual environment..."
|
||||
DeterminePythonVersion
|
||||
|
|
@ -700,6 +858,12 @@ if [ "$1" = "--le-auto-phase2" ]; then
|
|||
virtualenv --no-site-packages --python "$LE_PYTHON" "$VENV_PATH" > /dev/null
|
||||
fi
|
||||
|
||||
if [ -n "$BOOTSTRAP_VERSION" ]; then
|
||||
echo "$BOOTSTRAP_VERSION" > "$BOOTSTRAP_VERSION_PATH"
|
||||
elif [ -n "$PREV_BOOTSTRAP_VERSION" ]; then
|
||||
echo "$PREV_BOOTSTRAP_VERSION" > "$BOOTSTRAP_VERSION_PATH"
|
||||
fi
|
||||
|
||||
say "Installing Python packages..."
|
||||
TEMP_DIR=$(TempDir)
|
||||
trap 'rm -rf "$TEMP_DIR"' EXIT
|
||||
|
|
@ -766,29 +930,41 @@ cffi==1.10.0 \
|
|||
--hash=sha256:285ab352552f52f1398c912556d4d36d4ea9b8450e5c65d03809bf9886755533 \
|
||||
--hash=sha256:5576644b859197da7bbd8f8c7c2fb5dcc6cd505cadb42992d5f104c013f8a214 \
|
||||
--hash=sha256:b3b02911eb1f6ada203b0763ba924234629b51586f72a21faacc638269f4ced5
|
||||
ConfigArgParse==0.10.0 \
|
||||
--hash=sha256:3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7
|
||||
ConfigArgParse==0.12.0 \
|
||||
--hash=sha256:28cd7d67669651f2a4518367838c49539457504584a139709b2b8f6c208ef339
|
||||
configobj==5.0.6 \
|
||||
--hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
|
||||
cryptography==1.9 \
|
||||
--hash=sha256:469a9d3d851038f1eb7d7f77bb08bb4775b41483372be450e25b293fe57bd59e \
|
||||
--hash=sha256:533143321d15c8743f91eec5c5f495c1b5cad9a25de8f6dab01eddd6b416903e \
|
||||
--hash=sha256:2230c186182d773064d06242e0fa604cd718bfff28aa9c5ae73d7e426e98a151 \
|
||||
--hash=sha256:3dc94ed5a26b8553a325767358f505c0a43e0c89df078647f77a4d022ddcdc57 \
|
||||
--hash=sha256:2eb8297b877cb6b56216750fa7017c9f5786bec8afd6a0f1aaace02cbfb6195f \
|
||||
--hash=sha256:025a96e48164106f2082b00f42bf430cf21f09e203e42585a712e420b75cbff0 \
|
||||
--hash=sha256:61eb3534f8ed2415dd708b28919205d523f220e4cd5b8165844edfdd4a649b8e \
|
||||
--hash=sha256:5474fe5ce6b517d3086e0231b6ad88f8978c551c4379f91c3d619c308490f0d7 \
|
||||
--hash=sha256:5ff169869624e23767d70db274f13a9ea4e97c029425a1224aa5e049e84ce2af \
|
||||
--hash=sha256:c26e057a2de13e97e708328d295c5ac4cd3eab4a5c42ce727dd1a53316034b8a \
|
||||
--hash=sha256:7db719432648f14ea33edffc5f75330c595804eac86ca916528b35ce50a8bfd6 \
|
||||
--hash=sha256:ca72537a7064bb80e34b6908e576ffc8e2c2cad29a7168f48d0999df089695c3 \
|
||||
--hash=sha256:2a5e577f5d2093e51486b4ec02b51bb5adb165b98fee99929d5af0813e90b469 \
|
||||
--hash=sha256:9d9da8bac2e31003d092f5ef6981a725c77c4e9a30638436884d61ad39f9a1ee \
|
||||
--hash=sha256:fab8ec6866e384d9827d5dc02a1383e991a6c05c54f818316c4b829e56ca2ba3 \
|
||||
--hash=sha256:365eb804362e581c9a02e7a610b30514f07dd77b2a38aed338eb5192446bbc58 \
|
||||
--hash=sha256:2908f709f02711dbb10561a9f154d2f7d1792385e2341e9708539cc4ecfb8667 \
|
||||
--hash=sha256:5518337022718029e367d982642f3e3523541e098ad671672a90b82474c84882
|
||||
cryptography==2.0.2 \
|
||||
--hash=sha256:187ae17358436d2c760f28c2aeb02fefa3f37647a9c5b6f7f7c3e83cd1c5a972 \
|
||||
--hash=sha256:19e43a13bbf52028dd1e810c803f2ad8880d0692d772f98d42e1eaf34bdee3d6 \
|
||||
--hash=sha256:da9291502cbc87dc0284a20c56876e4d2e68deac61cc43df4aec934e44ca97b1 \
|
||||
--hash=sha256:0954f8813095f581669330e0a2d5e726c33ac7f450c1458fac58bab54595e516 \
|
||||
--hash=sha256:d68b0cc40a8432ed3fc84876c519de704d6001800ec22b136e75ae841910c45b \
|
||||
--hash=sha256:2f8ad9580ab4da645cfea52a91d2da99a49a1e76616d8be68441a986fad652b0 \
|
||||
--hash=sha256:cc00b4511294f5f6b65c4e77a1a9c62f52490a63d2c120f3872176b40a82351e \
|
||||
--hash=sha256:cf896020f6a9f095a547b3d672c8db1ef2ed71fca11250731fa1d4a4cb8b1590 \
|
||||
--hash=sha256:e0fdb8322206fa02aa38f71519ff75dce2eb481b7e1110e2936795cb376bb6ee \
|
||||
--hash=sha256:277538466657ca5d6637f80be100242f9831d75138b788d718edd3aab34621f8 \
|
||||
--hash=sha256:2c77eb0560f54ce654ab82d6b2a64327a71ee969b29022bf9746ca311c9f5069 \
|
||||
--hash=sha256:755a7853b679e79d0a799351c092a9b0271f95ff54c8dd8823d8b527a2926a86 \
|
||||
--hash=sha256:77197a2d525e761cdd4c771180b4bd0d80703654c6385e4311cbbbe2beb56fa1 \
|
||||
--hash=sha256:eb8bb79d0ab00c931c8333b745f06fec481a51c52d70acd4ee95d6093ba5c386 \
|
||||
--hash=sha256:131f61de82ef28f3e20beb4bfc24f9692d28cecfd704e20e6c7f070f7793013a \
|
||||
--hash=sha256:ac35435974b2e27cd4520f29c191d7da36f4189aa3264e52c4c6c6d089ab6142 \
|
||||
--hash=sha256:04b6ea99daa2a8460728794213d76d45ad58ea247dc7e7ff148d7dd726e87863 \
|
||||
--hash=sha256:2b9442f8b4c3d575f6cc3db0e856034e0f5a9d55ecd636f52d8c496795b26952 \
|
||||
--hash=sha256:b3d3b3ecba1fe1bdb6f180770a137f877c8f07571f7b2934bb269475bcf0e5e8 \
|
||||
--hash=sha256:670a58c0d75cb0e78e73dd003bd96d4440bbb1f2bc041dcf7b81767ca4fb0ce9 \
|
||||
--hash=sha256:5af84d23bdb86b5e90aca263df1424b43f1748480bfcde3ac2a3cbe622612468 \
|
||||
--hash=sha256:ba22e8eefabdd7aca37d0c0c00d2274000d2cebb5cce9e5a710cb55bf8797b31 \
|
||||
--hash=sha256:b798b22fa7e92b439547323b8b719d217f1e1b7677585cfeeedf3b55c70bb7fb \
|
||||
--hash=sha256:59cff28af8cce96cb7e94a459726e1d88f6f5fa75097f9dcbebd99118d64ea4c \
|
||||
--hash=sha256:fe859e445abc9ba9e97950ddafb904e23234c4ecb76b0fae6c86e80592ce464a \
|
||||
--hash=sha256:655f3c474067f1e277430f23cc0549f0b1dc99b82aec6e53f80b9b2db7f76f11 \
|
||||
--hash=sha256:0ebc2be053c9a03a2f3e20a466e87bf12a51586b3c79bd2a22171b073a805346 \
|
||||
--hash=sha256:01e6e60654df64cca53733cda39446d67100c819c181d403afb120e0d2a71e1b \
|
||||
--hash=sha256:d46f4e5d455cb5563685c52ef212696f0a6cc1ea627603218eabbd8a095291d8 \
|
||||
--hash=sha256:3780b2663ee7ebb37cb83263326e3cd7f8b2ea439c448539d4b87de12c8d06ab
|
||||
enum34==1.1.2 \
|
||||
--hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \
|
||||
--hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501
|
||||
|
|
@ -895,18 +1071,18 @@ letsencrypt==0.7.0 \
|
|||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==0.16.0 \
|
||||
--hash=sha256:e1cc2479f4f149a7128b67192c3f5f6c111b6b9ddcac421ebee8ac5030d5b09b \
|
||||
--hash=sha256:795801fd6b06b32060e364ac045312e6b26c6272d5ca32878277e5a2afdee186
|
||||
acme==0.16.0 \
|
||||
--hash=sha256:31592a744f7a6e7cbb4c5daf2deebc9af6b03997d6f80e5becc203ab8694edcf \
|
||||
--hash=sha256:538b69134cc50bdcdcc081b844c85158509022c61d7abc1f44216beeb95de9cd
|
||||
certbot-apache==0.16.0 \
|
||||
--hash=sha256:337f84f391c7d7c31d84376e7a8c882ac119112a4aabceadd1a7de6a2f01ca06 \
|
||||
--hash=sha256:f1f37b56e1ceb0a28ccf51d54ca34444e6a708448845ef25372e223b9a82c4d4
|
||||
certbot-nginx==0.16.0 \
|
||||
--hash=sha256:1d57428202f8e7abdd99c3ddbcf374aad5f69c4262fe8dae53d2016e4ae04ded \
|
||||
--hash=sha256:77711655514d707ddf728195f00b2f6cdd1ad9db52440276b4a67664479c6954
|
||||
certbot==0.17.0 \
|
||||
--hash=sha256:64c25c7123357feffded6408660bc6f5c7d493dd635ae172081d21473075a86a \
|
||||
--hash=sha256:43f5b26c3f314d14babf79a3bdf3522e4fc9eef867a0681c426f113c650a669c
|
||||
acme==0.17.0 \
|
||||
--hash=sha256:501710171633af13fc52aa61d0277a6fe335f7477db5810e72239aaf4f3a09e7 \
|
||||
--hash=sha256:3ccbe4aaeb98c77b98ee4093b4e4adb76a1a24cbdfec0130c489c206f1d9b66e
|
||||
certbot-apache==0.17.0 \
|
||||
--hash=sha256:17a7e8d7526d838610e68b96cf052af17c4055655b76b06d1cbc74857d90a216 \
|
||||
--hash=sha256:29b9e7bc5eaaff6dc4bce8398e35eeacdf346126aad68cac3d41bb87df20a6b9
|
||||
certbot-nginx==0.17.0 \
|
||||
--hash=sha256:980c9a33a79ab839a089a0085ff0c5414f01f47b6db26ed342df25916658cec9 \
|
||||
--hash=sha256:e573f8b4283172755c07b9cca8a8da7ef2d31b4df763881394b5339b2d42994a
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
|
@ -934,6 +1110,7 @@ anything goes wrong, it will exit with a non-zero status code.
|
|||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
from __future__ import print_function
|
||||
from distutils.version import StrictVersion
|
||||
from hashlib import sha256
|
||||
from os.path import join
|
||||
from pipes import quote
|
||||
|
|
@ -968,12 +1145,14 @@ except ImportError:
|
|||
from urllib.parse import urlparse # 3.4
|
||||
|
||||
|
||||
__version__ = 1, 1, 1
|
||||
__version__ = 1, 3, 0
|
||||
PIP_VERSION = '9.0.1'
|
||||
|
||||
|
||||
# wheel has a conditional dependency on argparse:
|
||||
maybe_argparse = (
|
||||
[('https://pypi.python.org/packages/source/a/argparse/'
|
||||
[('https://pypi.python.org/packages/18/dd/'
|
||||
'e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/'
|
||||
'argparse-1.4.0.tar.gz',
|
||||
'62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')]
|
||||
if version_info < (2, 7, 0) else [])
|
||||
|
|
@ -981,13 +1160,19 @@ maybe_argparse = (
|
|||
|
||||
PACKAGES = maybe_argparse + [
|
||||
# Pip has no dependencies, as it vendors everything:
|
||||
('https://pypi.python.org/packages/source/p/pip/pip-8.0.3.tar.gz',
|
||||
'30f98b66f3fe1069c529a491597d34a1c224a68640c82caf2ade5f88aa1405e8'),
|
||||
('https://pypi.python.org/packages/11/b6/'
|
||||
'abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/'
|
||||
'pip-{0}.tar.gz'
|
||||
.format(PIP_VERSION),
|
||||
'09f243e1a7b461f654c26a725fa373211bb7ff17a9300058b205c61658ca940d'),
|
||||
# This version of setuptools has only optional dependencies:
|
||||
('https://pypi.python.org/packages/source/s/setuptools/'
|
||||
('https://pypi.python.org/packages/69/65/'
|
||||
'4c544cde88d4d876cdf5cbc5f3f15d02646477756d89547e9a7ecd6afa76/'
|
||||
'setuptools-20.2.2.tar.gz',
|
||||
'24fcfc15364a9fe09a220f37d2dcedc849795e3de3e4b393ee988e66a9cbd85a'),
|
||||
('https://pypi.python.org/packages/source/w/wheel/wheel-0.29.0.tar.gz',
|
||||
('https://pypi.python.org/packages/c9/1d/'
|
||||
'bd19e691fd4cfe908c76c429fe6e4436c9e83583c4414b54f6c85471954a/'
|
||||
'wheel-0.29.0.tar.gz',
|
||||
'1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648')
|
||||
]
|
||||
|
||||
|
|
@ -1037,11 +1222,21 @@ def hashed_download(url, temp, digest):
|
|||
|
||||
|
||||
def main():
|
||||
pip_version = StrictVersion(check_output(['pip', '--version'])
|
||||
.decode('utf-8').split()[1])
|
||||
min_pip_version = StrictVersion(PIP_VERSION)
|
||||
if pip_version >= min_pip_version:
|
||||
return 0
|
||||
has_pip_cache = pip_version >= StrictVersion('6.0')
|
||||
|
||||
temp = mkdtemp(prefix='pipstrap-')
|
||||
try:
|
||||
downloads = [hashed_download(url, temp, digest)
|
||||
for url, digest in PACKAGES]
|
||||
check_output('pip install --no-index --no-deps -U ' +
|
||||
# Disable cache since we're not using it and it otherwise
|
||||
# sometimes throws permission warnings:
|
||||
('--no-cache-dir ' if has_pip_cache else '') +
|
||||
' '.join(quote(d) for d in downloads),
|
||||
shell=True)
|
||||
except HashError as exc:
|
||||
|
|
@ -1100,20 +1295,15 @@ UNLIKELY_EOF
|
|||
rm -rf "$VENV_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d "$OLD_VENV_PATH" -a ! -L "$OLD_VENV_PATH" ]; then
|
||||
rm -rf "$OLD_VENV_PATH"
|
||||
ln -s "$VENV_PATH" "$OLD_VENV_PATH"
|
||||
fi
|
||||
|
||||
say "Installation succeeded."
|
||||
fi
|
||||
if [ -n "$SUDO" ]; then
|
||||
# SUDO is su wrapper or sudo
|
||||
say "Requesting root privileges to run certbot..."
|
||||
say " $VENV_BIN/letsencrypt" "$@"
|
||||
fi
|
||||
if [ -z "$SUDO_ENV" ] ; then
|
||||
# SUDO is su wrapper / noop
|
||||
$SUDO "$VENV_BIN/letsencrypt" "$@"
|
||||
else
|
||||
# sudo
|
||||
$SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
|
||||
fi
|
||||
"$VENV_BIN/letsencrypt" "$@"
|
||||
|
||||
else
|
||||
# Phase 1: Upgrade certbot-auto if necessary, then self-invoke.
|
||||
|
|
@ -1124,12 +1314,14 @@ else
|
|||
# package). Phase 2 checks the version of the locally installed certbot.
|
||||
|
||||
if [ ! -f "$VENV_BIN/letsencrypt" ]; then
|
||||
if [ "$HELP" = 1 ]; then
|
||||
echo "$USAGE"
|
||||
exit 0
|
||||
if [ -z "$OLD_VENV_PATH" -o ! -f "$OLD_VENV_PATH/bin/letsencrypt" ]; then
|
||||
if [ "$HELP" = 1 ]; then
|
||||
echo "$USAGE"
|
||||
exit 0
|
||||
fi
|
||||
# If it looks like we've never bootstrapped before, bootstrap:
|
||||
Bootstrap
|
||||
fi
|
||||
# If it looks like we've never bootstrapped before, bootstrap:
|
||||
Bootstrap
|
||||
fi
|
||||
if [ "$OS_PACKAGES_ONLY" = 1 ]; then
|
||||
say "OS packages installed."
|
||||
|
|
@ -1289,13 +1481,13 @@ UNLIKELY_EOF
|
|||
say "Replacing certbot-auto..."
|
||||
# Clone permissions with cp. chmod and chown don't have a --reference
|
||||
# option on macOS or BSD, and stat -c on Linux is stat -f on macOS and BSD:
|
||||
$SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
$SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
# Using mv rather than cp leaves the old file descriptor pointing to the
|
||||
# original copy so the shell can continue to read it unmolested. mv across
|
||||
# filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the
|
||||
# cp is unlikely to fail (esp. under sudo) if the rm doesn't.
|
||||
$SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
|
||||
# cp is unlikely to fail if the rm doesn't.
|
||||
mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
|
||||
fi # A newer version is available.
|
||||
fi # Self-upgrading is allowed.
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -23,11 +23,14 @@ fi
|
|||
if [ -z "$XDG_DATA_HOME" ]; then
|
||||
XDG_DATA_HOME=~/.local/share
|
||||
fi
|
||||
VENV_NAME="letsencrypt"
|
||||
if [ -z "$VENV_PATH" ]; then
|
||||
VENV_PATH="$XDG_DATA_HOME/$VENV_NAME"
|
||||
# We export these values so they are preserved properly if this script is
|
||||
# rerun with sudo/su where $HOME/$XDG_DATA_HOME may have a different value.
|
||||
export OLD_VENV_PATH="$XDG_DATA_HOME/letsencrypt"
|
||||
export VENV_PATH="/opt/eff.org/certbot/venv"
|
||||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
|
||||
LE_AUTO_VERSION="{{ LE_AUTO_VERSION }}"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
|
|
@ -49,6 +52,7 @@ Help for certbot itself cannot be provided until it is installed.
|
|||
implies --non-interactive
|
||||
|
||||
All arguments are accepted and forwarded to the Certbot client when run."
|
||||
export CERTBOT_AUTO="$0"
|
||||
|
||||
for arg in "$@" ; do
|
||||
case "$arg" in
|
||||
|
|
@ -77,7 +81,7 @@ for arg in "$@" ; do
|
|||
h)
|
||||
HELP=1;;
|
||||
n)
|
||||
ASSUME_YES=1;;
|
||||
NONINTERACTIVE=1;;
|
||||
q)
|
||||
QUIET=1;;
|
||||
v)
|
||||
|
|
@ -93,8 +97,8 @@ if [ $BASENAME = "letsencrypt-auto" ]; then
|
|||
HELP=0
|
||||
fi
|
||||
|
||||
# Set ASSUME_YES to 1 if QUIET (i.e. --quiet implies --non-interactive)
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
# Set ASSUME_YES to 1 if QUIET or NONINTERACTIVE
|
||||
if [ "$QUIET" = 1 -o "$NONINTERACTIVE" = 1 ]; then
|
||||
ASSUME_YES=1
|
||||
fi
|
||||
|
||||
|
|
@ -119,16 +123,18 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# certbot-auto needs root access to bootstrap OS dependencies, and
|
||||
# certbot itself needs root access for almost all modes of operation
|
||||
# The "normal" case is that sudo is used for the steps that need root, but
|
||||
# this script *can* be run as root (not recommended), or fall back to using
|
||||
# `su`. Auto-detection can be overridden by explicitly setting the
|
||||
# environment variable LE_AUTO_SUDO to 'sudo', 'sudo_su' or '' as used below.
|
||||
# Certbot itself needs root access for almost all modes of operation.
|
||||
# certbot-auto needs root access to bootstrap OS dependencies and install
|
||||
# Certbot at a protected path so it can be safely run as root. To accomplish
|
||||
# this, this script will attempt to run itself as root if it doesn't have the
|
||||
# necessary privileges by using `sudo` or falling back to `su` if it is not
|
||||
# available. The mechanism used to obtain root access can be set explicitly by
|
||||
# setting the environment variable LE_AUTO_SUDO to 'sudo', 'su', 'su_sudo',
|
||||
# 'SuSudo', or '' as used below.
|
||||
|
||||
# Because the parameters in `su -c` has to be a string,
|
||||
# we need to properly escape it.
|
||||
su_sudo() {
|
||||
SuSudo() {
|
||||
args=""
|
||||
# This `while` loop iterates over all parameters given to this function.
|
||||
# For each parameter, all `'` will be replace by `'"'"'`, and the escaped string
|
||||
|
|
@ -147,34 +153,47 @@ su_sudo() {
|
|||
su root -c "$args"
|
||||
}
|
||||
|
||||
SUDO_ENV=""
|
||||
export CERTBOT_AUTO="$0"
|
||||
if [ -n "${LE_AUTO_SUDO+x}" ]; then
|
||||
case "$LE_AUTO_SUDO" in
|
||||
su_sudo|su)
|
||||
SUDO=su_sudo
|
||||
;;
|
||||
sudo)
|
||||
SUDO=sudo
|
||||
SUDO_ENV="CERTBOT_AUTO=$0"
|
||||
;;
|
||||
'') ;; # Nothing to do for plain root method.
|
||||
*)
|
||||
error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
exit 1
|
||||
esac
|
||||
say "Using preset root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
else
|
||||
if test "`id -u`" -ne "0" ; then
|
||||
if $EXISTS sudo 1>/dev/null 2>&1; then
|
||||
SUDO=sudo
|
||||
SUDO_ENV="CERTBOT_AUTO=$0"
|
||||
else
|
||||
say \"sudo\" is not available, will use \"su\" for installation steps...
|
||||
SUDO=su_sudo
|
||||
fi
|
||||
# Sets the environment variable SUDO to be the name of the program or function
|
||||
# to call to get root access. If this script already has root privleges, SUDO
|
||||
# is set to an empty string. The value in SUDO should be run with the command
|
||||
# to called with root privileges as arguments.
|
||||
SetRootAuthMechanism() {
|
||||
SUDO=""
|
||||
if [ -n "${LE_AUTO_SUDO+x}" ]; then
|
||||
case "$LE_AUTO_SUDO" in
|
||||
SuSudo|su_sudo|su)
|
||||
SUDO=SuSudo
|
||||
;;
|
||||
sudo)
|
||||
SUDO="sudo -E"
|
||||
;;
|
||||
'') ;; # Nothing to do for plain root method.
|
||||
*)
|
||||
error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
exit 1
|
||||
esac
|
||||
say "Using preset root authorization mechanism '$LE_AUTO_SUDO'."
|
||||
else
|
||||
SUDO=
|
||||
if test "`id -u`" -ne "0" ; then
|
||||
if $EXISTS sudo 1>/dev/null 2>&1; then
|
||||
SUDO="sudo -E"
|
||||
else
|
||||
say \"sudo\" is not available, will use \"su\" for installation steps...
|
||||
SUDO=SuSudo
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$1" = "--cb-auto-has-root" ]; then
|
||||
shift 1
|
||||
elif [ "$1" != "--le-auto-phase2" ]; then
|
||||
# if $1 is --le-auto-phase2, we've executed this branch before
|
||||
SetRootAuthMechanism
|
||||
if [ -n "$SUDO" ]; then
|
||||
echo "Requesting to rerun $0 with root privileges..."
|
||||
$SUDO "$0" --cb-auto-has-root "$@"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
@ -248,23 +267,41 @@ DeterminePythonVersion() {
|
|||
{{ bootstrappers/smartos.sh }}
|
||||
{{ bootstrappers/mageia_common.sh }}
|
||||
|
||||
# Install required OS packages:
|
||||
Bootstrap() {
|
||||
if [ "$NO_BOOTSTRAP" = 1 ]; then
|
||||
return
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
# Set Bootstrap to the function that installs OS dependencies on this system
|
||||
# and BOOTSTRAP_VERSION to the unique identifier for the current version of
|
||||
# that function. If Bootstrap is set to a function that doesn't install any
|
||||
# packages (either because --no-bootstrap was included on the command line or
|
||||
# we don't know how to bootstrap on this system), BOOTSTRAP_VERSION is not set.
|
||||
if [ "$NO_BOOTSTRAP" = 1 ]; then
|
||||
Bootstrap() {
|
||||
:
|
||||
}
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
Bootstrap() {
|
||||
BootstrapMessage "Debian-based OSes"
|
||||
BootstrapDebCommon
|
||||
elif [ -f /etc/mageia-release ]; then
|
||||
# Mageia has both /etc/mageia-release and /etc/redhat-release
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapDebCommon $BOOTSTRAP_DEB_COMMON_VERSION"
|
||||
elif [ -f /etc/mageia-release ]; then
|
||||
# Mageia has both /etc/mageia-release and /etc/redhat-release
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Mageia" BootstrapMageiaCommon
|
||||
elif [ -f /etc/redhat-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapMageiaCommon $BOOTSTRAP_MAGEIA_COMMON_VERSION"
|
||||
elif [ -f /etc/redhat-release ]; then
|
||||
Bootstrap() {
|
||||
BootstrapMessage "RedHat-based OSes"
|
||||
BootstrapRpmCommon
|
||||
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
|
||||
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
|
||||
Bootstrap() {
|
||||
BootstrapMessage "openSUSE-based OSes"
|
||||
BootstrapSuseCommon
|
||||
elif [ -f /etc/arch-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapSuseCommon $BOOTSTRAP_SUSE_COMMON_VERSION"
|
||||
elif [ -f /etc/arch-release ]; then
|
||||
Bootstrap() {
|
||||
if [ "$DEBUG" = 1 ]; then
|
||||
BootstrapMessage "Archlinux"
|
||||
BootstrapArchCommon
|
||||
|
|
@ -276,25 +313,76 @@ Bootstrap() {
|
|||
error "--debug flag."
|
||||
exit 1
|
||||
fi
|
||||
elif [ -f /etc/manjaro-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapArchCommon $BOOTSTRAP_ARCH_COMMON_VERSION"
|
||||
elif [ -f /etc/manjaro-release ]; then
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon
|
||||
elif [ -f /etc/gentoo-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapArchCommon $BOOTSTRAP_ARCH_COMMON_VERSION"
|
||||
elif [ -f /etc/gentoo-release ]; then
|
||||
Bootstrap() {
|
||||
DeprecationBootstrap "Gentoo" BootstrapGentooCommon
|
||||
elif uname | grep -iq FreeBSD ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapGentooCommon $BOOTSTRAP_GENTOO_COMMON_VERSION"
|
||||
elif uname | grep -iq FreeBSD ; then
|
||||
Bootstrap() {
|
||||
DeprecationBootstrap "FreeBSD" BootstrapFreeBsd
|
||||
elif uname | grep -iq Darwin ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapFreeBsd $BOOTSTRAP_FREEBSD_VERSION"
|
||||
elif uname | grep -iq Darwin ; then
|
||||
Bootstrap() {
|
||||
DeprecationBootstrap "macOS" BootstrapMac
|
||||
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapMac $BOOTSTRAP_MAC_VERSION"
|
||||
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
|
||||
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
|
||||
elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
|
||||
Bootstrap() {
|
||||
ExperimentalBootstrap "Joyent SmartOS Zone" BootstrapSmartOS
|
||||
else
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapSmartOS $BOOTSTRAP_SMARTOS_VERSION"
|
||||
else
|
||||
Bootstrap() {
|
||||
error "Sorry, I don't know how to bootstrap Certbot on your operating system!"
|
||||
error
|
||||
error "You will need to install OS dependencies, configure virtualenv, and run pip install manually."
|
||||
error "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites"
|
||||
error "for more info."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Sets PREV_BOOTSTRAP_VERSION to the identifier for the bootstrap script used
|
||||
# to install OS dependencies on this system. PREV_BOOTSTRAP_VERSION isn't set
|
||||
# if it is unknown how OS dependencies were installed on this system.
|
||||
SetPrevBootstrapVersion() {
|
||||
if [ -f $BOOTSTRAP_VERSION_PATH ]; then
|
||||
PREV_BOOTSTRAP_VERSION=$(cat "$BOOTSTRAP_VERSION_PATH")
|
||||
# The list below only contains bootstrap version strings that existed before
|
||||
# we started writing them to disk.
|
||||
#
|
||||
# DO NOT MODIFY THIS LIST UNLESS YOU KNOW WHAT YOU'RE DOING!
|
||||
elif grep -Fqx "$BOOTSTRAP_VERSION" << "UNLIKELY_EOF"
|
||||
BootstrapDebCommon 1
|
||||
BootstrapMageiaCommon 1
|
||||
BootstrapRpmCommon 1
|
||||
BootstrapSuseCommon 1
|
||||
BootstrapArchCommon 1
|
||||
BootstrapGentooCommon 1
|
||||
BootstrapFreeBsd 1
|
||||
BootstrapMac 1
|
||||
BootstrapSmartOS 1
|
||||
UNLIKELY_EOF
|
||||
then
|
||||
# If there's no bootstrap version saved to disk, but the currently selected
|
||||
# bootstrap script is from before we started saving the version number,
|
||||
# return the currently selected version to prevent us from rebootstrapping
|
||||
# unnecessarily.
|
||||
PREV_BOOTSTRAP_VERSION="$BOOTSTRAP_VERSION"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -308,18 +396,39 @@ if [ "$1" = "--le-auto-phase2" ]; then
|
|||
# Phase 2: Create venv, install LE, and run.
|
||||
|
||||
shift 1 # the --le-auto-phase2 arg
|
||||
if [ -f "$VENV_BIN/letsencrypt" ]; then
|
||||
# --version output ran through grep due to python-cryptography DeprecationWarnings
|
||||
# grep for both certbot and letsencrypt until certbot and shim packages have been released
|
||||
INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2)
|
||||
if [ -z "$INSTALLED_VERSION" ]; then
|
||||
error "Error: couldn't get currently installed version for $VENV_BIN/letsencrypt: " 1>&2
|
||||
"$VENV_BIN/letsencrypt" --version
|
||||
exit 1
|
||||
SetPrevBootstrapVersion
|
||||
|
||||
INSTALLED_VERSION="none"
|
||||
if [ -d "$VENV_PATH" ]; then
|
||||
# If the selected Bootstrap function isn't a noop and it differs from the
|
||||
# previously used version
|
||||
if [ -n "$BOOTSTRAP_VERSION" -a "$BOOTSTRAP_VERSION" != "$PREV_BOOTSTRAP_VERSION" ]; then
|
||||
# if non-interactive mode or stdin and stdout are connected to a terminal
|
||||
if [ \( "$NONINTERACTIVE" = 1 \) -o \( \( -t 0 \) -a \( -t 1 \) \) ]; then
|
||||
rm -rf "$VENV_PATH"
|
||||
"$0" "$@"
|
||||
exit 0
|
||||
else
|
||||
error "Skipping upgrade because new OS dependencies may need to be installed."
|
||||
error
|
||||
error "To upgrade to a newer version, please run this script again manually so you can"
|
||||
error "approve changes or with --non-interactive on the command line to automatically"
|
||||
error "install any required packages."
|
||||
# Set INSTALLED_VERSION to be the same so we don't update the venv
|
||||
INSTALLED_VERSION="$LE_AUTO_VERSION"
|
||||
fi
|
||||
elif [ -f "$VENV_BIN/letsencrypt" ]; then
|
||||
# --version output ran through grep due to python-cryptography DeprecationWarnings
|
||||
# grep for both certbot and letsencrypt until certbot and shim packages have been released
|
||||
INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2)
|
||||
if [ -z "$INSTALLED_VERSION" ]; then
|
||||
error "Error: couldn't get currently installed version for $VENV_BIN/letsencrypt: " 1>&2
|
||||
"$VENV_BIN/letsencrypt" --version
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
INSTALLED_VERSION="none"
|
||||
fi
|
||||
|
||||
if [ "$LE_AUTO_VERSION" != "$INSTALLED_VERSION" ]; then
|
||||
say "Creating virtual environment..."
|
||||
DeterminePythonVersion
|
||||
|
|
@ -330,6 +439,12 @@ if [ "$1" = "--le-auto-phase2" ]; then
|
|||
virtualenv --no-site-packages --python "$LE_PYTHON" "$VENV_PATH" > /dev/null
|
||||
fi
|
||||
|
||||
if [ -n "$BOOTSTRAP_VERSION" ]; then
|
||||
echo "$BOOTSTRAP_VERSION" > "$BOOTSTRAP_VERSION_PATH"
|
||||
elif [ -n "$PREV_BOOTSTRAP_VERSION" ]; then
|
||||
echo "$PREV_BOOTSTRAP_VERSION" > "$BOOTSTRAP_VERSION_PATH"
|
||||
fi
|
||||
|
||||
say "Installing Python packages..."
|
||||
TEMP_DIR=$(TempDir)
|
||||
trap 'rm -rf "$TEMP_DIR"' EXIT
|
||||
|
|
@ -385,20 +500,15 @@ UNLIKELY_EOF
|
|||
rm -rf "$VENV_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d "$OLD_VENV_PATH" -a ! -L "$OLD_VENV_PATH" ]; then
|
||||
rm -rf "$OLD_VENV_PATH"
|
||||
ln -s "$VENV_PATH" "$OLD_VENV_PATH"
|
||||
fi
|
||||
|
||||
say "Installation succeeded."
|
||||
fi
|
||||
if [ -n "$SUDO" ]; then
|
||||
# SUDO is su wrapper or sudo
|
||||
say "Requesting root privileges to run certbot..."
|
||||
say " $VENV_BIN/letsencrypt" "$@"
|
||||
fi
|
||||
if [ -z "$SUDO_ENV" ] ; then
|
||||
# SUDO is su wrapper / noop
|
||||
$SUDO "$VENV_BIN/letsencrypt" "$@"
|
||||
else
|
||||
# sudo
|
||||
$SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
|
||||
fi
|
||||
"$VENV_BIN/letsencrypt" "$@"
|
||||
|
||||
else
|
||||
# Phase 1: Upgrade certbot-auto if necessary, then self-invoke.
|
||||
|
|
@ -409,12 +519,14 @@ else
|
|||
# package). Phase 2 checks the version of the locally installed certbot.
|
||||
|
||||
if [ ! -f "$VENV_BIN/letsencrypt" ]; then
|
||||
if [ "$HELP" = 1 ]; then
|
||||
echo "$USAGE"
|
||||
exit 0
|
||||
if [ -z "$OLD_VENV_PATH" -o ! -f "$OLD_VENV_PATH/bin/letsencrypt" ]; then
|
||||
if [ "$HELP" = 1 ]; then
|
||||
echo "$USAGE"
|
||||
exit 0
|
||||
fi
|
||||
# If it looks like we've never bootstrapped before, bootstrap:
|
||||
Bootstrap
|
||||
fi
|
||||
# If it looks like we've never bootstrapped before, bootstrap:
|
||||
Bootstrap
|
||||
fi
|
||||
if [ "$OS_PACKAGES_ONLY" = 1 ]; then
|
||||
say "OS packages installed."
|
||||
|
|
@ -445,13 +557,13 @@ UNLIKELY_EOF
|
|||
say "Replacing certbot-auto..."
|
||||
# Clone permissions with cp. chmod and chown don't have a --reference
|
||||
# option on macOS or BSD, and stat -c on Linux is stat -f on macOS and BSD:
|
||||
$SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
$SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
# Using mv rather than cp leaves the old file descriptor pointing to the
|
||||
# original copy so the shell can continue to read it unmolested. mv across
|
||||
# filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the
|
||||
# cp is unlikely to fail (esp. under sudo) if the rm doesn't.
|
||||
$SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
|
||||
# cp is unlikely to fail if the rm doesn't.
|
||||
mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
|
||||
fi # A newer version is available.
|
||||
fi # Self-upgrading is allowed.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# If new packages are installed by BootstrapArchCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_ARCH_COMMON_VERSION=1
|
||||
|
||||
BootstrapArchCommon() {
|
||||
# Tested with:
|
||||
# - ArchLinux (x86_64)
|
||||
|
|
@ -18,17 +22,17 @@ BootstrapArchCommon() {
|
|||
"
|
||||
|
||||
# pacman -T exits with 127 if there are missing dependencies
|
||||
missing=$($SUDO pacman -T $deps) || true
|
||||
missing=$(pacman -T $deps) || true
|
||||
|
||||
if [ "$ASSUME_YES" = 1 ]; then
|
||||
noconfirm="--noconfirm"
|
||||
fi
|
||||
|
||||
if [ "$missing" ]; then
|
||||
if [ "$QUIET" = 1]; then
|
||||
$SUDO pacman -S --needed $missing $noconfirm > /dev/null
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
pacman -S --needed $missing $noconfirm > /dev/null
|
||||
else
|
||||
$SUDO pacman -S --needed $missing $noconfirm
|
||||
pacman -S --needed $missing $noconfirm
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# If new packages are installed by BootstrapDebCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_DEB_COMMON_VERSION=1
|
||||
|
||||
BootstrapDebCommon() {
|
||||
# Current version tested with:
|
||||
#
|
||||
|
|
@ -21,7 +25,7 @@ BootstrapDebCommon() {
|
|||
QUIET_FLAG='-qq'
|
||||
fi
|
||||
|
||||
$SUDO apt-get $QUIET_FLAG update || error apt-get update hit problems but continuing anyway...
|
||||
apt-get $QUIET_FLAG update || error apt-get update hit problems but continuing anyway...
|
||||
|
||||
# virtualenv binary can be found in different packages depending on
|
||||
# distro version (#346)
|
||||
|
|
@ -71,13 +75,13 @@ BootstrapDebCommon() {
|
|||
esac
|
||||
fi
|
||||
if [ "$add_backports" = 1 ]; then
|
||||
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
|
||||
$SUDO apt-get $QUIET_FLAG update
|
||||
sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
|
||||
apt-get $QUIET_FLAG update
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ "$add_backports" != 0 ]; then
|
||||
$SUDO apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
|
||||
apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
|
||||
augeas_pkg=
|
||||
fi
|
||||
}
|
||||
|
|
@ -96,7 +100,7 @@ BootstrapDebCommon() {
|
|||
# XXX add a case for ubuntu PPAs
|
||||
fi
|
||||
|
||||
$SUDO apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends \
|
||||
apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends \
|
||||
python \
|
||||
python-dev \
|
||||
$virtualenv \
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
# If new packages are installed by BootstrapFreeBsd below, this version number
|
||||
# must be increased.
|
||||
BOOTSTRAP_FREEBSD_VERSION=1
|
||||
|
||||
BootstrapFreeBsd() {
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
QUIET_FLAG="--quiet"
|
||||
fi
|
||||
|
||||
$SUDO pkg install -Ay $QUIET_FLAG \
|
||||
pkg install -Ay $QUIET_FLAG \
|
||||
python \
|
||||
py27-virtualenv \
|
||||
augeas \
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# If new packages are installed by BootstrapGentooCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_GENTOO_COMMON_VERSION=1
|
||||
|
||||
BootstrapGentooCommon() {
|
||||
PACKAGES="
|
||||
dev-lang/python:2.7
|
||||
|
|
@ -15,13 +19,13 @@ BootstrapGentooCommon() {
|
|||
|
||||
case "$PACKAGE_MANAGER" in
|
||||
(paludis)
|
||||
$SUDO cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
|
||||
cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
|
||||
;;
|
||||
(pkgcore)
|
||||
$SUDO pmerge --noreplace --oneshot $ASK_OPTION $PACKAGES
|
||||
pmerge --noreplace --oneshot $ASK_OPTION $PACKAGES
|
||||
;;
|
||||
(portage|*)
|
||||
$SUDO emerge --noreplace --oneshot $ASK_OPTION $PACKAGES
|
||||
emerge --noreplace --oneshot $ASK_OPTION $PACKAGES
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# If new packages are installed by BootstrapMac below, this version number must
|
||||
# be increased.
|
||||
BOOTSTRAP_MAC_VERSION=1
|
||||
|
||||
BootstrapMac() {
|
||||
if hash brew 2>/dev/null; then
|
||||
say "Using Homebrew to install dependencies..."
|
||||
|
|
@ -6,7 +10,7 @@ BootstrapMac() {
|
|||
elif hash port 2>/dev/null; then
|
||||
say "Using MacPorts to install dependencies..."
|
||||
pkgman=port
|
||||
pkgcmd="$SUDO port install"
|
||||
pkgcmd="port install"
|
||||
else
|
||||
say "No Homebrew/MacPorts; installing Homebrew..."
|
||||
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
|
|
@ -26,8 +30,8 @@ BootstrapMac() {
|
|||
# Workaround for _dlopen not finding augeas on macOS
|
||||
if [ "$pkgman" = "port" ] && ! [ -e "/usr/local/lib/libaugeas.dylib" ] && [ -e "/opt/local/lib/libaugeas.dylib" ]; then
|
||||
say "Applying augeas workaround"
|
||||
$SUDO mkdir -p /usr/local/lib/
|
||||
$SUDO ln -s /opt/local/lib/libaugeas.dylib /usr/local/lib/
|
||||
mkdir -p /usr/local/lib/
|
||||
ln -s /opt/local/lib/libaugeas.dylib /usr/local/lib/
|
||||
fi
|
||||
|
||||
if ! hash pip 2>/dev/null; then
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
# If new packages are installed by BootstrapMageiaCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_MAGEIA_COMMON_VERSION=1
|
||||
|
||||
BootstrapMageiaCommon() {
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
QUIET_FLAG='--quiet'
|
||||
fi
|
||||
|
||||
if ! $SUDO urpmi --force $QUIET_FLAG \
|
||||
if ! urpmi --force $QUIET_FLAG \
|
||||
python \
|
||||
libpython-devel \
|
||||
python-virtualenv
|
||||
|
|
@ -12,7 +16,7 @@ BootstrapMageiaCommon() {
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if ! $SUDO urpmi --force $QUIET_FLAG \
|
||||
if ! urpmi --force $QUIET_FLAG \
|
||||
git \
|
||||
gcc \
|
||||
python-augeas \
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# If new packages are installed by BootstrapRpmCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_RPM_COMMON_VERSION=1
|
||||
|
||||
BootstrapRpmCommon() {
|
||||
# Tested with:
|
||||
# - Fedora 20, 21, 22, 23 (x64)
|
||||
|
|
@ -24,9 +28,9 @@ BootstrapRpmCommon() {
|
|||
QUIET_FLAG='--quiet'
|
||||
fi
|
||||
|
||||
if ! $SUDO $tool list *virtualenv >/dev/null 2>&1; then
|
||||
if ! $tool list *virtualenv >/dev/null 2>&1; then
|
||||
echo "To use Certbot, packages from the EPEL repository need to be installed."
|
||||
if ! $SUDO $tool list epel-release >/dev/null 2>&1; then
|
||||
if ! $tool list epel-release >/dev/null 2>&1; then
|
||||
error "Enable the EPEL repository and try running Certbot again."
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -38,7 +42,7 @@ BootstrapRpmCommon() {
|
|||
/bin/echo -e "\e[0K\rEnabling the EPEL repository in 1 seconds..."
|
||||
sleep 1s
|
||||
fi
|
||||
if ! $SUDO $tool install $yes_flag $QUIET_FLAG epel-release; then
|
||||
if ! $tool install $yes_flag $QUIET_FLAG epel-release; then
|
||||
error "Could not enable EPEL. Aborting bootstrap!"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -54,9 +58,8 @@ BootstrapRpmCommon() {
|
|||
ca-certificates
|
||||
"
|
||||
|
||||
# Some distros and older versions of current distros use a "python27"
|
||||
# instead of "python" naming convention. Try both conventions.
|
||||
if $SUDO $tool list python >/dev/null 2>&1; then
|
||||
# Most RPM distros use the "python" or "python-" naming convention. Let's try that first.
|
||||
if $tool list python >/dev/null 2>&1; then
|
||||
pkgs="$pkgs
|
||||
python
|
||||
python-devel
|
||||
|
|
@ -64,6 +67,20 @@ BootstrapRpmCommon() {
|
|||
python-tools
|
||||
python-pip
|
||||
"
|
||||
# Fedora 26 starts to use the prefix python2 for python2 based packages.
|
||||
# this elseif is theoretically for any Fedora over version 26:
|
||||
elif $tool list python2 >/dev/null 2>&1; then
|
||||
pkgs="$pkgs
|
||||
python2
|
||||
python2-libs
|
||||
python2-setuptools
|
||||
python2-devel
|
||||
python2-virtualenv
|
||||
python2-tools
|
||||
python2-pip
|
||||
"
|
||||
# Some distros and older versions of current distros use a "python27"
|
||||
# instead of the "python" or "python-" naming convention.
|
||||
else
|
||||
pkgs="$pkgs
|
||||
python27
|
||||
|
|
@ -74,13 +91,13 @@ BootstrapRpmCommon() {
|
|||
"
|
||||
fi
|
||||
|
||||
if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then
|
||||
if $tool list installed "httpd" >/dev/null 2>&1; then
|
||||
pkgs="$pkgs
|
||||
mod_ssl
|
||||
"
|
||||
fi
|
||||
|
||||
if ! $SUDO $tool install $yes_flag $QUIET_FLAG $pkgs; then
|
||||
if ! $tool install $yes_flag $QUIET_FLAG $pkgs; then
|
||||
error "Could not install OS dependencies. Aborting bootstrap!"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# If new packages are installed by BootstrapSmartOS below, this version number
|
||||
# must be increased.
|
||||
BOOTSTRAP_SMARTOS_VERSION=1
|
||||
|
||||
BootstrapSmartOS() {
|
||||
pkgin update
|
||||
pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv'
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# If new packages are installed by BootstrapSuseCommon below, this version
|
||||
# number must be increased.
|
||||
BOOTSTRAP_SUSE_COMMON_VERSION=1
|
||||
|
||||
BootstrapSuseCommon() {
|
||||
# SLE12 don't have python-virtualenv
|
||||
|
||||
|
|
@ -10,7 +14,7 @@ BootstrapSuseCommon() {
|
|||
QUIET_FLAG='-qq'
|
||||
fi
|
||||
|
||||
$SUDO zypper $QUIET_FLAG $zypper_flags in $install_flags \
|
||||
zypper $QUIET_FLAG $zypper_flags in $install_flags \
|
||||
python \
|
||||
python-devel \
|
||||
python-virtualenv \
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
certbot==0.16.0 \
|
||||
--hash=sha256:e1cc2479f4f149a7128b67192c3f5f6c111b6b9ddcac421ebee8ac5030d5b09b \
|
||||
--hash=sha256:795801fd6b06b32060e364ac045312e6b26c6272d5ca32878277e5a2afdee186
|
||||
acme==0.16.0 \
|
||||
--hash=sha256:31592a744f7a6e7cbb4c5daf2deebc9af6b03997d6f80e5becc203ab8694edcf \
|
||||
--hash=sha256:538b69134cc50bdcdcc081b844c85158509022c61d7abc1f44216beeb95de9cd
|
||||
certbot-apache==0.16.0 \
|
||||
--hash=sha256:337f84f391c7d7c31d84376e7a8c882ac119112a4aabceadd1a7de6a2f01ca06 \
|
||||
--hash=sha256:f1f37b56e1ceb0a28ccf51d54ca34444e6a708448845ef25372e223b9a82c4d4
|
||||
certbot-nginx==0.16.0 \
|
||||
--hash=sha256:1d57428202f8e7abdd99c3ddbcf374aad5f69c4262fe8dae53d2016e4ae04ded \
|
||||
--hash=sha256:77711655514d707ddf728195f00b2f6cdd1ad9db52440276b4a67664479c6954
|
||||
certbot==0.17.0 \
|
||||
--hash=sha256:64c25c7123357feffded6408660bc6f5c7d493dd635ae172081d21473075a86a \
|
||||
--hash=sha256:43f5b26c3f314d14babf79a3bdf3522e4fc9eef867a0681c426f113c650a669c
|
||||
acme==0.17.0 \
|
||||
--hash=sha256:501710171633af13fc52aa61d0277a6fe335f7477db5810e72239aaf4f3a09e7 \
|
||||
--hash=sha256:3ccbe4aaeb98c77b98ee4093b4e4adb76a1a24cbdfec0130c489c206f1d9b66e
|
||||
certbot-apache==0.17.0 \
|
||||
--hash=sha256:17a7e8d7526d838610e68b96cf052af17c4055655b76b06d1cbc74857d90a216 \
|
||||
--hash=sha256:29b9e7bc5eaaff6dc4bce8398e35eeacdf346126aad68cac3d41bb87df20a6b9
|
||||
certbot-nginx==0.17.0 \
|
||||
--hash=sha256:980c9a33a79ab839a089a0085ff0c5414f01f47b6db26ed342df25916658cec9 \
|
||||
--hash=sha256:e573f8b4283172755c07b9cca8a8da7ef2d31b4df763881394b5339b2d42994a
|
||||
|
|
|
|||
|
|
@ -58,29 +58,41 @@ cffi==1.10.0 \
|
|||
--hash=sha256:285ab352552f52f1398c912556d4d36d4ea9b8450e5c65d03809bf9886755533 \
|
||||
--hash=sha256:5576644b859197da7bbd8f8c7c2fb5dcc6cd505cadb42992d5f104c013f8a214 \
|
||||
--hash=sha256:b3b02911eb1f6ada203b0763ba924234629b51586f72a21faacc638269f4ced5
|
||||
ConfigArgParse==0.10.0 \
|
||||
--hash=sha256:3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7
|
||||
ConfigArgParse==0.12.0 \
|
||||
--hash=sha256:28cd7d67669651f2a4518367838c49539457504584a139709b2b8f6c208ef339
|
||||
configobj==5.0.6 \
|
||||
--hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
|
||||
cryptography==1.9 \
|
||||
--hash=sha256:469a9d3d851038f1eb7d7f77bb08bb4775b41483372be450e25b293fe57bd59e \
|
||||
--hash=sha256:533143321d15c8743f91eec5c5f495c1b5cad9a25de8f6dab01eddd6b416903e \
|
||||
--hash=sha256:2230c186182d773064d06242e0fa604cd718bfff28aa9c5ae73d7e426e98a151 \
|
||||
--hash=sha256:3dc94ed5a26b8553a325767358f505c0a43e0c89df078647f77a4d022ddcdc57 \
|
||||
--hash=sha256:2eb8297b877cb6b56216750fa7017c9f5786bec8afd6a0f1aaace02cbfb6195f \
|
||||
--hash=sha256:025a96e48164106f2082b00f42bf430cf21f09e203e42585a712e420b75cbff0 \
|
||||
--hash=sha256:61eb3534f8ed2415dd708b28919205d523f220e4cd5b8165844edfdd4a649b8e \
|
||||
--hash=sha256:5474fe5ce6b517d3086e0231b6ad88f8978c551c4379f91c3d619c308490f0d7 \
|
||||
--hash=sha256:5ff169869624e23767d70db274f13a9ea4e97c029425a1224aa5e049e84ce2af \
|
||||
--hash=sha256:c26e057a2de13e97e708328d295c5ac4cd3eab4a5c42ce727dd1a53316034b8a \
|
||||
--hash=sha256:7db719432648f14ea33edffc5f75330c595804eac86ca916528b35ce50a8bfd6 \
|
||||
--hash=sha256:ca72537a7064bb80e34b6908e576ffc8e2c2cad29a7168f48d0999df089695c3 \
|
||||
--hash=sha256:2a5e577f5d2093e51486b4ec02b51bb5adb165b98fee99929d5af0813e90b469 \
|
||||
--hash=sha256:9d9da8bac2e31003d092f5ef6981a725c77c4e9a30638436884d61ad39f9a1ee \
|
||||
--hash=sha256:fab8ec6866e384d9827d5dc02a1383e991a6c05c54f818316c4b829e56ca2ba3 \
|
||||
--hash=sha256:365eb804362e581c9a02e7a610b30514f07dd77b2a38aed338eb5192446bbc58 \
|
||||
--hash=sha256:2908f709f02711dbb10561a9f154d2f7d1792385e2341e9708539cc4ecfb8667 \
|
||||
--hash=sha256:5518337022718029e367d982642f3e3523541e098ad671672a90b82474c84882
|
||||
cryptography==2.0.2 \
|
||||
--hash=sha256:187ae17358436d2c760f28c2aeb02fefa3f37647a9c5b6f7f7c3e83cd1c5a972 \
|
||||
--hash=sha256:19e43a13bbf52028dd1e810c803f2ad8880d0692d772f98d42e1eaf34bdee3d6 \
|
||||
--hash=sha256:da9291502cbc87dc0284a20c56876e4d2e68deac61cc43df4aec934e44ca97b1 \
|
||||
--hash=sha256:0954f8813095f581669330e0a2d5e726c33ac7f450c1458fac58bab54595e516 \
|
||||
--hash=sha256:d68b0cc40a8432ed3fc84876c519de704d6001800ec22b136e75ae841910c45b \
|
||||
--hash=sha256:2f8ad9580ab4da645cfea52a91d2da99a49a1e76616d8be68441a986fad652b0 \
|
||||
--hash=sha256:cc00b4511294f5f6b65c4e77a1a9c62f52490a63d2c120f3872176b40a82351e \
|
||||
--hash=sha256:cf896020f6a9f095a547b3d672c8db1ef2ed71fca11250731fa1d4a4cb8b1590 \
|
||||
--hash=sha256:e0fdb8322206fa02aa38f71519ff75dce2eb481b7e1110e2936795cb376bb6ee \
|
||||
--hash=sha256:277538466657ca5d6637f80be100242f9831d75138b788d718edd3aab34621f8 \
|
||||
--hash=sha256:2c77eb0560f54ce654ab82d6b2a64327a71ee969b29022bf9746ca311c9f5069 \
|
||||
--hash=sha256:755a7853b679e79d0a799351c092a9b0271f95ff54c8dd8823d8b527a2926a86 \
|
||||
--hash=sha256:77197a2d525e761cdd4c771180b4bd0d80703654c6385e4311cbbbe2beb56fa1 \
|
||||
--hash=sha256:eb8bb79d0ab00c931c8333b745f06fec481a51c52d70acd4ee95d6093ba5c386 \
|
||||
--hash=sha256:131f61de82ef28f3e20beb4bfc24f9692d28cecfd704e20e6c7f070f7793013a \
|
||||
--hash=sha256:ac35435974b2e27cd4520f29c191d7da36f4189aa3264e52c4c6c6d089ab6142 \
|
||||
--hash=sha256:04b6ea99daa2a8460728794213d76d45ad58ea247dc7e7ff148d7dd726e87863 \
|
||||
--hash=sha256:2b9442f8b4c3d575f6cc3db0e856034e0f5a9d55ecd636f52d8c496795b26952 \
|
||||
--hash=sha256:b3d3b3ecba1fe1bdb6f180770a137f877c8f07571f7b2934bb269475bcf0e5e8 \
|
||||
--hash=sha256:670a58c0d75cb0e78e73dd003bd96d4440bbb1f2bc041dcf7b81767ca4fb0ce9 \
|
||||
--hash=sha256:5af84d23bdb86b5e90aca263df1424b43f1748480bfcde3ac2a3cbe622612468 \
|
||||
--hash=sha256:ba22e8eefabdd7aca37d0c0c00d2274000d2cebb5cce9e5a710cb55bf8797b31 \
|
||||
--hash=sha256:b798b22fa7e92b439547323b8b719d217f1e1b7677585cfeeedf3b55c70bb7fb \
|
||||
--hash=sha256:59cff28af8cce96cb7e94a459726e1d88f6f5fa75097f9dcbebd99118d64ea4c \
|
||||
--hash=sha256:fe859e445abc9ba9e97950ddafb904e23234c4ecb76b0fae6c86e80592ce464a \
|
||||
--hash=sha256:655f3c474067f1e277430f23cc0549f0b1dc99b82aec6e53f80b9b2db7f76f11 \
|
||||
--hash=sha256:0ebc2be053c9a03a2f3e20a466e87bf12a51586b3c79bd2a22171b073a805346 \
|
||||
--hash=sha256:01e6e60654df64cca53733cda39446d67100c819c181d403afb120e0d2a71e1b \
|
||||
--hash=sha256:d46f4e5d455cb5563685c52ef212696f0a6cc1ea627603218eabbd8a095291d8 \
|
||||
--hash=sha256:3780b2663ee7ebb37cb83263326e3cd7f8b2ea439c448539d4b87de12c8d06ab
|
||||
enum34==1.1.2 \
|
||||
--hash=sha256:2475d7fcddf5951e92ff546972758802de5260bf409319a9f1934e6bbc8b1dc7 \
|
||||
--hash=sha256:35907defb0f992b75ab7788f65fedc1cf20ffa22688e0e6f6f12afc06b3ea501
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ anything goes wrong, it will exit with a non-zero status code.
|
|||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
from __future__ import print_function
|
||||
from distutils.version import StrictVersion
|
||||
from hashlib import sha256
|
||||
from os.path import join
|
||||
from pipes import quote
|
||||
|
|
@ -55,12 +56,14 @@ except ImportError:
|
|||
from urllib.parse import urlparse # 3.4
|
||||
|
||||
|
||||
__version__ = 1, 1, 1
|
||||
__version__ = 1, 3, 0
|
||||
PIP_VERSION = '9.0.1'
|
||||
|
||||
|
||||
# wheel has a conditional dependency on argparse:
|
||||
maybe_argparse = (
|
||||
[('https://pypi.python.org/packages/source/a/argparse/'
|
||||
[('https://pypi.python.org/packages/18/dd/'
|
||||
'e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/'
|
||||
'argparse-1.4.0.tar.gz',
|
||||
'62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')]
|
||||
if version_info < (2, 7, 0) else [])
|
||||
|
|
@ -68,13 +71,19 @@ maybe_argparse = (
|
|||
|
||||
PACKAGES = maybe_argparse + [
|
||||
# Pip has no dependencies, as it vendors everything:
|
||||
('https://pypi.python.org/packages/source/p/pip/pip-8.0.3.tar.gz',
|
||||
'30f98b66f3fe1069c529a491597d34a1c224a68640c82caf2ade5f88aa1405e8'),
|
||||
('https://pypi.python.org/packages/11/b6/'
|
||||
'abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/'
|
||||
'pip-{0}.tar.gz'
|
||||
.format(PIP_VERSION),
|
||||
'09f243e1a7b461f654c26a725fa373211bb7ff17a9300058b205c61658ca940d'),
|
||||
# This version of setuptools has only optional dependencies:
|
||||
('https://pypi.python.org/packages/source/s/setuptools/'
|
||||
('https://pypi.python.org/packages/69/65/'
|
||||
'4c544cde88d4d876cdf5cbc5f3f15d02646477756d89547e9a7ecd6afa76/'
|
||||
'setuptools-20.2.2.tar.gz',
|
||||
'24fcfc15364a9fe09a220f37d2dcedc849795e3de3e4b393ee988e66a9cbd85a'),
|
||||
('https://pypi.python.org/packages/source/w/wheel/wheel-0.29.0.tar.gz',
|
||||
('https://pypi.python.org/packages/c9/1d/'
|
||||
'bd19e691fd4cfe908c76c429fe6e4436c9e83583c4414b54f6c85471954a/'
|
||||
'wheel-0.29.0.tar.gz',
|
||||
'1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648')
|
||||
]
|
||||
|
||||
|
|
@ -124,11 +133,21 @@ def hashed_download(url, temp, digest):
|
|||
|
||||
|
||||
def main():
|
||||
pip_version = StrictVersion(check_output(['pip', '--version'])
|
||||
.decode('utf-8').split()[1])
|
||||
min_pip_version = StrictVersion(PIP_VERSION)
|
||||
if pip_version >= min_pip_version:
|
||||
return 0
|
||||
has_pip_cache = pip_version >= StrictVersion('6.0')
|
||||
|
||||
temp = mkdtemp(prefix='pipstrap-')
|
||||
try:
|
||||
downloads = [hashed_download(url, temp, digest)
|
||||
for url, digest in PACKAGES]
|
||||
check_output('pip install --no-index --no-deps -U ' +
|
||||
# Disable cache since we're not using it and it otherwise
|
||||
# sometimes throws permission warnings:
|
||||
('--no-cache-dir ' if has_pip_cache else '') +
|
||||
' '.join(quote(d) for d in downloads),
|
||||
shell=True)
|
||||
except HashError as exc:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
|
|||
from contextlib import contextmanager
|
||||
from functools import partial
|
||||
from json import dumps
|
||||
from os import chmod, environ
|
||||
from os import chmod, environ, makedirs
|
||||
from os.path import abspath, dirname, exists, join
|
||||
import re
|
||||
from shutil import copy, rmtree
|
||||
|
|
@ -118,12 +118,13 @@ LE_AUTO_PATH = join(dirname(tests_dir()), 'letsencrypt-auto')
|
|||
|
||||
|
||||
@contextmanager
|
||||
def ephemeral_dir():
|
||||
def temp_paths():
|
||||
"""Creates and deletes paths for letsencrypt-auto and its venv."""
|
||||
dir = mkdtemp(prefix='le-test-')
|
||||
try:
|
||||
yield dir
|
||||
yield join(dir, 'letsencrypt-auto'), join(dir, 'venv')
|
||||
finally:
|
||||
rmtree(dir)
|
||||
rmtree(dir, ignore_errors=True)
|
||||
|
||||
|
||||
def out_and_err(command, input=None, shell=False, env=None):
|
||||
|
|
@ -160,21 +161,20 @@ def signed(content, private_key_name='signing.key'):
|
|||
return out
|
||||
|
||||
|
||||
def install_le_auto(contents, venv_dir):
|
||||
def install_le_auto(contents, install_path):
|
||||
"""Install some given source code as the letsencrypt-auto script at the
|
||||
root level of a virtualenv.
|
||||
|
||||
:arg contents: The contents of the built letsencrypt-auto script
|
||||
:arg venv_dir: The path under which to install the script
|
||||
:arg install_path: The path where to install the script
|
||||
|
||||
"""
|
||||
venv_le_auto_path = join(venv_dir, 'letsencrypt-auto')
|
||||
with open(venv_le_auto_path, 'w') as le_auto:
|
||||
with open(install_path, 'w') as le_auto:
|
||||
le_auto.write(contents)
|
||||
chmod(venv_le_auto_path, S_IRUSR | S_IXUSR)
|
||||
chmod(install_path, S_IRUSR | S_IXUSR)
|
||||
|
||||
|
||||
def run_le_auto(venv_dir, base_url, **kwargs):
|
||||
def run_le_auto(le_auto_path, venv_dir, base_url, **kwargs):
|
||||
"""Run the prebuilt version of letsencrypt-auto, returning stdout and
|
||||
stderr strings.
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ def run_le_auto(venv_dir, base_url, **kwargs):
|
|||
|
||||
"""
|
||||
env = environ.copy()
|
||||
d = dict(XDG_DATA_HOME=venv_dir,
|
||||
d = dict(VENV_PATH=venv_dir,
|
||||
# URL to PyPI-style JSON that tell us the latest released version
|
||||
# of LE:
|
||||
LE_AUTO_JSON_URL=base_url + 'certbot/json',
|
||||
|
|
@ -201,7 +201,7 @@ iQIDAQAB
|
|||
**kwargs)
|
||||
env.update(d)
|
||||
return out_and_err(
|
||||
join(venv_dir, 'letsencrypt-auto') + ' --version',
|
||||
le_auto_path + ' --version',
|
||||
shell=True,
|
||||
env=env)
|
||||
|
||||
|
|
@ -213,10 +213,12 @@ def set_le_script_version(venv_dir, version):
|
|||
print its version.
|
||||
|
||||
"""
|
||||
with open(join(venv_dir, 'letsencrypt', 'bin', 'letsencrypt'), 'w') as script:
|
||||
letsencrypt_path = join(venv_dir, 'bin', 'letsencrypt')
|
||||
with open(letsencrypt_path, 'w') as script:
|
||||
script.write("#!/usr/bin/env python\n"
|
||||
"from sys import stderr\n"
|
||||
"stderr.write('letsencrypt %s\\n')" % version)
|
||||
chmod(letsencrypt_path, S_IRUSR | S_IXUSR)
|
||||
|
||||
|
||||
class AutoTests(TestCase):
|
||||
|
|
@ -237,6 +239,11 @@ class AutoTests(TestCase):
|
|||
test suites.
|
||||
|
||||
"""
|
||||
NEW_LE_AUTO = build_le_auto(
|
||||
version='99.9.9',
|
||||
requirements='letsencrypt==99.9.9 --hash=sha256:1cc14d61ab424cdee446f51e50f1123f8482ec740587fe78626c933bba2873a0')
|
||||
NEW_LE_AUTO_SIG = signed(NEW_LE_AUTO)
|
||||
|
||||
def test_successes(self):
|
||||
"""Exercise most branches of letsencrypt-auto.
|
||||
|
||||
|
|
@ -252,20 +259,16 @@ class AutoTests(TestCase):
|
|||
the next, saving code.
|
||||
|
||||
"""
|
||||
NEW_LE_AUTO = build_le_auto(
|
||||
version='99.9.9',
|
||||
requirements='letsencrypt==99.9.9 --hash=sha256:1cc14d61ab424cdee446f51e50f1123f8482ec740587fe78626c933bba2873a0')
|
||||
NEW_LE_AUTO_SIG = signed(NEW_LE_AUTO)
|
||||
|
||||
with ephemeral_dir() as venv_dir:
|
||||
with temp_paths() as (le_auto_path, venv_dir):
|
||||
# This serves a PyPI page with a higher version, a GitHub-alike
|
||||
# with a corresponding le-auto script, and a matching signature.
|
||||
resources = {'certbot/json': dumps({'releases': {'99.9.9': None}}),
|
||||
'v99.9.9/letsencrypt-auto': NEW_LE_AUTO,
|
||||
'v99.9.9/letsencrypt-auto.sig': NEW_LE_AUTO_SIG}
|
||||
'v99.9.9/letsencrypt-auto': self.NEW_LE_AUTO,
|
||||
'v99.9.9/letsencrypt-auto.sig': self.NEW_LE_AUTO_SIG}
|
||||
with serving(resources) as base_url:
|
||||
run_letsencrypt_auto = partial(
|
||||
run_le_auto,
|
||||
le_auto_path,
|
||||
venv_dir,
|
||||
base_url,
|
||||
PIP_FIND_LINKS=join(tests_dir(),
|
||||
|
|
@ -274,7 +277,7 @@ class AutoTests(TestCase):
|
|||
|
||||
# Test when a phase-1 upgrade is needed, there's no LE binary
|
||||
# installed, and pip hashes verify:
|
||||
install_le_auto(build_le_auto(version='50.0.0'), venv_dir)
|
||||
install_le_auto(build_le_auto(version='50.0.0'), le_auto_path)
|
||||
out, err = run_letsencrypt_auto()
|
||||
ok_(re.match(r'letsencrypt \d+\.\d+\.\d+',
|
||||
err.strip().splitlines()[-1]))
|
||||
|
|
@ -291,16 +294,28 @@ class AutoTests(TestCase):
|
|||
self.assertFalse('Upgrading certbot-auto ' in out)
|
||||
self.assertFalse('Creating virtual environment...' in out)
|
||||
|
||||
# Test when a phase-1 upgrade is not needed but a phase-2
|
||||
# upgrade is:
|
||||
def test_phase2_upgrade(self):
|
||||
"""Test a phase-2 upgrade without a phase-1 upgrade."""
|
||||
with temp_paths() as (le_auto_path, venv_dir):
|
||||
resources = {'certbot/json': dumps({'releases': {'99.9.9': None}}),
|
||||
'v99.9.9/letsencrypt-auto': self.NEW_LE_AUTO,
|
||||
'v99.9.9/letsencrypt-auto.sig': self.NEW_LE_AUTO_SIG}
|
||||
with serving(resources) as base_url:
|
||||
venv_bin = join(venv_dir, 'bin')
|
||||
makedirs(venv_bin)
|
||||
set_le_script_version(venv_dir, '0.0.1')
|
||||
out, err = run_letsencrypt_auto()
|
||||
|
||||
install_le_auto(self.NEW_LE_AUTO, le_auto_path)
|
||||
pip_find_links=join(tests_dir(), 'fake-letsencrypt', 'dist')
|
||||
out, err = run_le_auto(le_auto_path, venv_dir, base_url,
|
||||
PIP_FIND_LINKS=pip_find_links)
|
||||
|
||||
self.assertFalse('Upgrading certbot-auto ' in out)
|
||||
self.assertTrue('Creating virtual environment...' in out)
|
||||
|
||||
def test_openssl_failure(self):
|
||||
"""Make sure we stop if the openssl signature check fails."""
|
||||
with ephemeral_dir() as venv_dir:
|
||||
with temp_paths() as (le_auto_path, venv_dir):
|
||||
# Serve an unrelated hash signed with the good key (easier than
|
||||
# making a bad key, and a mismatch is a mismatch):
|
||||
resources = {'': '<a href="certbot/">certbot/</a>',
|
||||
|
|
@ -308,9 +323,9 @@ class AutoTests(TestCase):
|
|||
'v99.9.9/letsencrypt-auto': build_le_auto(version='99.9.9'),
|
||||
'v99.9.9/letsencrypt-auto.sig': signed('something else')}
|
||||
with serving(resources) as base_url:
|
||||
copy(LE_AUTO_PATH, venv_dir)
|
||||
copy(LE_AUTO_PATH, le_auto_path)
|
||||
try:
|
||||
out, err = run_le_auto(venv_dir, base_url)
|
||||
out, err = run_le_auto(le_auto_path, venv_dir, base_url)
|
||||
except CalledProcessError as exc:
|
||||
eq_(exc.returncode, 1)
|
||||
self.assertTrue("Couldn't verify signature of downloaded "
|
||||
|
|
@ -320,7 +335,7 @@ class AutoTests(TestCase):
|
|||
|
||||
def test_pip_failure(self):
|
||||
"""Make sure pip stops us if there is a hash mismatch."""
|
||||
with ephemeral_dir() as venv_dir:
|
||||
with temp_paths() as (le_auto_path, venv_dir):
|
||||
resources = {'': '<a href="certbot/">certbot/</a>',
|
||||
'certbot/json': dumps({'releases': {'99.9.9': None}})}
|
||||
with serving(resources) as base_url:
|
||||
|
|
@ -329,14 +344,14 @@ class AutoTests(TestCase):
|
|||
build_le_auto(
|
||||
version='99.9.9',
|
||||
requirements='configobj==5.0.6 --hash=sha256:badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb'),
|
||||
venv_dir)
|
||||
le_auto_path)
|
||||
try:
|
||||
out, err = run_le_auto(venv_dir, base_url)
|
||||
out, err = run_le_auto(le_auto_path, venv_dir, base_url)
|
||||
except CalledProcessError as exc:
|
||||
eq_(exc.returncode, 1)
|
||||
self.assertTrue("THESE PACKAGES DO NOT MATCH THE HASHES "
|
||||
"FROM THE REQUIREMENTS FILE" in exc.output)
|
||||
ok_(not exists(join(venv_dir, 'letsencrypt')),
|
||||
ok_(not exists(venv_dir),
|
||||
msg="The virtualenv was left around, even though "
|
||||
"installation didn't succeed. We shouldn't do "
|
||||
"this, as it foils our detection of whether we "
|
||||
|
|
|
|||
3
tox.ini
3
tox.ini
|
|
@ -85,11 +85,14 @@ deps =
|
|||
configobj==4.7.2
|
||||
cryptography==1.2.3
|
||||
enum34==0.9.23
|
||||
google-api-python-client==1.5
|
||||
idna==2.0
|
||||
ipaddress==1.0.16
|
||||
mock==1.0.1
|
||||
ndg-httpsclient==0.3.2
|
||||
oauth2client==2.0
|
||||
parsedatetime==1.4
|
||||
pyasn1-modules==0.0.5
|
||||
pyasn1==0.1.9
|
||||
pyparsing==1.5.6
|
||||
pyrfc3339==1.0
|
||||
|
|
|
|||
Loading…
Reference in a new issue