Merge branch 'master' into rename

This commit is contained in:
Brad Warren
2016-05-12 14:44:23 -07:00
33 changed files with 1710 additions and 327 deletions
+11 -4
View File
@@ -40,11 +40,18 @@ Because not all operating systems have packages yet, we provide a temporary
solution via the ``certbot-auto`` wrapper script, which obtains some
dependencies from your OS and puts others in a python virtual environment::
user@webserver:~$ git clone https://github.com/certbot/certbot
user@webserver:~$ cd certbot
user@webserver:~/certbot$ ./certbot-auto --help
user@webserver:~$ wget https://dl.eff.org/certbot-auto
user@webserver:~$ chmod a+x ./certbot-auto
user@webserver:~$ ./certbot-auto --help
Or for full command line help, type::
.. hint:: The certbot-auto download is protected by HTTPS, which is pretty good, but if you'd like to
double check the integrity of the ``certbot-auto`` script, you can use these steps for verification before running it::
user@server:~$ wget -N https://dl.eff.org/certbot-auto.asc
user@server:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2
user@server:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc certbot-auto
And for full command line help, you can type::
./certbot-auto --help all
+5 -3
View File
@@ -484,9 +484,11 @@ class ClientNetworkTest(unittest.TestCase):
def test_check_response_not_ok_jobj_no_error(self):
self.response.ok = False
self.response.json.return_value = {}
# pylint: disable=protected-access
self.assertRaises(
errors.ClientError, self.net._check_response, self.response)
with mock.patch('acme.client.messages.Error.from_json') as from_json:
from_json.side_effect = jose.DeserializationError
# pylint: disable=protected-access
self.assertRaises(
errors.ClientError, self.net._check_response, self.response)
def test_check_response_not_ok_jobj_error(self):
self.response.ok = False
+3 -12
View File
@@ -37,9 +37,9 @@ class Error(jose.JSONObjectWithFields, errors.Error):
)
)
typ = jose.Field('type')
typ = jose.Field('type', omitempty=True, default='about:blank')
title = jose.Field('title', omitempty=True)
detail = jose.Field('detail')
detail = jose.Field('detail', omitempty=True)
@property
def description(self):
@@ -143,12 +143,6 @@ class Directory(jose.JSONDeSerializable):
def __init__(self, jobj):
canon_jobj = util.map_keys(jobj, self._canon_key)
if not set(canon_jobj).issubset(
set(self._REGISTERED_TYPES).union(['meta'])):
# TODO: acme-spec is not clear about this: 'It is a JSON
# dictionary, whose keys are the "resource" values listed
# in {{https-requests}}'
raise ValueError('Wrong directory fields')
# TODO: check that everything is an absolute URL; acme-spec is
# not clear on that
self._jobj = canon_jobj
@@ -171,10 +165,7 @@ class Directory(jose.JSONDeSerializable):
@classmethod
def from_json(cls, jobj):
jobj['meta'] = cls.Meta.from_json(jobj.pop('meta', {}))
try:
return cls(jobj)
except ValueError as error:
raise jose.DeserializationError(str(error))
return cls(jobj)
class Resource(jose.JSONObjectWithFields):
+12 -5
View File
@@ -28,6 +28,14 @@ class ErrorTest(unittest.TestCase):
self.error_custom = Error(typ='custom', detail='bar')
self.jobj_cusom = {'type': 'custom', 'detail': 'bar'}
def test_default_typ(self):
from acme.messages import Error
self.assertEqual(Error().typ, 'about:blank')
def test_from_json_empty(self):
from acme.messages import Error
self.assertEqual(Error(), Error.from_json('{}'))
def test_from_json_hashable(self):
from acme.messages import Error
hash(Error.from_json(self.error.to_json()))
@@ -97,9 +105,9 @@ class DirectoryTest(unittest.TestCase):
),
})
def test_init_wrong_key_value_error(self):
def test_init_wrong_key_value_success(self): # pylint: disable=no-self-use
from acme.messages import Directory
self.assertRaises(ValueError, Directory, {'foo': 'bar'})
Directory({'foo': 'bar'})
def test_getitem(self):
self.assertEqual('reg', self.dir['new-reg'])
@@ -127,10 +135,9 @@ class DirectoryTest(unittest.TestCase):
},
})
def test_from_json_deserialization_error_on_wrong_key(self):
def test_from_json_deserialization_unknown_key_success(self): # pylint: disable=no-self-use
from acme.messages import Directory
self.assertRaises(
jose.DeserializationError, Directory.from_json, {'foo': 'bar'})
Directory.from_json({'foo': 'bar'})
class RegistrationTest(unittest.TestCase):
+1 -1
View File
@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.6.0.dev0'
version = '0.7.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
+1 -1
View File
@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.6.0.dev0'
version = '0.7.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
Executable
+1088
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.6.0.dev0'
version = '0.7.0.dev0'
install_requires = [
'certbot=={0}'.format(version),
+1 -1
View File
@@ -17,7 +17,7 @@ class RawNginxParser(object):
right_bracket = Literal("}").suppress()
semicolon = Literal(";").suppress()
space = White().suppress()
key = Word(alphanums + "_/")
key = Word(alphanums + "_/+-.")
# Matches anything that is not a special character AND any chars in single
# or double quotes
value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+")
+1 -1
View File
@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.6.0.dev0'
version = '0.7.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
+1 -1
View File
@@ -1,4 +1,4 @@
"""Certbot client."""
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
__version__ = '0.6.0.dev0'
__version__ = '0.7.0.dev0'
+23 -1
View File
@@ -37,8 +37,14 @@ helpful_parser = None
# should only be used for purposes where inability to detect letsencrypt-auto
# fails safely
LEAUTO = "letsencrypt-auto"
if "CERTBOT_AUTO" in os.environ:
# if we're here, this is probably going to be certbot-auto, unless the
# user saved the script under a different name
LEAUTO = os.path.basename(os.environ["CERTBOT_AUTO"])
fragment = os.path.join(".local", "share", "letsencrypt")
cli_command = "letsencrypt-auto" if fragment in sys.argv[0] else "certbot"
cli_command = LEAUTO if fragment in sys.argv[0] else "certbot"
# Argparse's help formatting has a lot of unhelpful peculiarities, so we want
# to replace as much of it as we can...
@@ -141,6 +147,22 @@ def usage_strings(plugins):
return USAGE % (apache_doc, nginx_doc), SHORT_USAGE
def possible_deprecation_warning(config):
"A deprecation warning for users with the old, not-self-upgrading letsencrypt-auto."
if cli_command != LEAUTO:
return
if config.no_self_upgrade:
# users setting --no-self-upgrade might be hanging on a clent version like 0.3.0
# or 0.5.0 which is the new script, but doesn't set CERTBOT_AUTO; they don't
# need warnings
return
if "CERTBOT_AUTO" not in os.environ:
logger.warn("You are running with an old copy of letsencrypt-auto that does "
"not receive updates, and is less reliable than more recent versions. "
"We recommend upgrading to the latest certbot-auto script, or using native "
"OS packages.")
class _Default(object):
"""A class to use as a default to detect if a value is set by a user"""
+1
View File
@@ -661,6 +661,7 @@ def main(cli_args=sys.argv[1:]):
le_util.make_or_verify_dir(
config.logs_dir, 0o700, os.geteuid(), "--strict-permissions" in cli_args)
setup_logging(config, _cli_log_handler, logfile='letsencrypt.log')
cli.possible_deprecation_warning(config)
logger.debug("certbot version: %s", certbot.__version__)
# do not log `config`, as it contains sensitive data (e.g. revoke --key)!
+3
View File
@@ -241,6 +241,9 @@ to serve all files under specified web root ({0})."""
elif exc.errno == errno.EACCES:
logger.debug("Challenges cleaned up but no permissions for %s",
root_path)
elif exc.errno == errno.ENOENT:
logger.debug("Challenges cleaned up, %s does not exists",
root_path)
else:
raise
+14 -1
View File
@@ -218,13 +218,26 @@ class AuthenticatorTest(unittest.TestCase):
self.auth.perform([self.achall])
os_error = OSError()
os_error.errno = errno.ENOENT
os_error.errno = errno.EPERM
mock_rmdir.side_effect = os_error
self.assertRaises(OSError, self.auth.cleanup, [self.achall])
self.assertFalse(os.path.exists(self.validation_path))
self.assertTrue(os.path.exists(self.root_challenge_path))
@mock.patch('os.rmdir')
def test_cleanup_file_not_exists(self, mock_rmdir):
self.auth.prepare()
self.auth.perform([self.achall])
os_error = OSError()
os_error.errno = errno.ENOENT
mock_rmdir.side_effect = os_error
self.auth.cleanup([self.achall])
self.assertFalse(os.path.exists(self.validation_path))
self.assertTrue(os.path.exists(self.root_challenge_path))
class WebrootActionTest(unittest.TestCase):
"""Tests for webroot argparse actions."""
+1 -1
View File
@@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__))
readme = read_file(os.path.join(here, 'README.rst'))
version = '0.6.0.dev0'
version = '0.7.0.dev0'
# This package is a simple shim around certbot-apache
+173 -96
View File
@@ -1,6 +1,6 @@
#!/bin/sh
#
# Download and run the latest release version of the Let's Encrypt client.
# Download and run the latest release version of the Certbot client.
#
# NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING
#
@@ -19,11 +19,36 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share}
VENV_NAME="letsencrypt"
VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"}
VENV_BIN="$VENV_PATH/bin"
LE_AUTO_VERSION="0.5.0"
LE_AUTO_VERSION="0.6.0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
to both this script and certbot will be downloaded and installed. After
ensuring you have the latest versions installed, certbot will be invoked with
all arguments you have provided.
Help for certbot itself cannot be provided until it is installed.
--debug attempt experimental installation
-h, --help print this help
-n, --non-interactive, --noninteractive run without asking for user input
--no-self-upgrade do not download updates
--os-packages-only install OS dependencies and exit
-v, --verbose provide more output
All arguments are accepted and forwarded to the Certbot client when run."
while getopts ":hnv" arg; do
case $arg in
h)
HELP=1;;
n)
ASSUME_YES=1;;
v)
VERBOSE=1;;
esac
done
# This script takes the same arguments as the main letsencrypt program, but it
# additionally responds to --verbose (more output) and --debug (allow support
# for experimental platforms)
for arg in "$@" ; do
case "$arg" in
--debug)
@@ -34,25 +59,26 @@ for arg in "$@" ; do
# Do not upgrade this script (also prevents client upgrades, because each
# copy of the script pins a hash of the python client)
NO_SELF_UPGRADE=1;;
--help)
HELP=1;;
--noninteractive|--non-interactive)
ASSUME_YES=1;;
--verbose)
VERBOSE=1;;
[!-]*|-*[!v]*|-)
# Anything that isn't -v, -vv, etc.: that is, anything that does not
# start with a -, contains anything that's not a v, or is just "-"
;;
*) # -v+ remains.
VERBOSE=1;;
esac
done
# letsencrypt-auto needs root access to bootstrap OS dependencies, and
# letsencrypt itself needs root access for almost all modes of operation
# 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`
SUDO_ENV=""
export CERTBOT_AUTO="$0"
if test "`id -u`" -ne "0" ; then
if command -v sudo 1>/dev/null 2>&1; then
SUDO=sudo
SUDO_ENV="CERTBOT_AUTO=$0"
else
echo \"sudo\" is not available, will use \"su\" for installation steps...
# Because the parameters in `su -c` has to be a string,
@@ -81,6 +107,12 @@ else
SUDO=
fi
if [ $BASENAME = "letsencrypt-auto" ]; then
# letsencrypt-auto does not respect --help or --yes for backwards compatibility
ASSUME_YES=1
HELP=0
fi
ExperimentalBootstrap() {
# Arguments: Platform name, bootstrap function name
if [ "$DEBUG" = 1 ]; then
@@ -151,30 +183,45 @@ BootstrapDebCommon() {
augeas_pkg="libaugeas0 augeas-lenses"
AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2`
if [ "$ASSUME_YES" = 1 ]; then
YES_FLAG="-y"
fi
AddBackportRepo() {
# ARGS:
BACKPORT_NAME="$1"
BACKPORT_SOURCELINE="$2"
echo "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME."
if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then
# This can theoretically error if sources.list.d is empty, but in that case we don't care.
if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then
/bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..."
sleep 1s
/bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..."
sleep 1s
/bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..."
sleep 1s
if echo $BACKPORT_NAME | grep -q wheezy ; then
/bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")'
if [ "$ASSUME_YES" = 1 ]; then
/bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..."
sleep 1s
/bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..."
sleep 1s
/bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..."
sleep 1s
add_backports=1
else
read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response
case $response in
[yY][eE][sS]|[yY]|"")
add_backports=1;;
*)
add_backports=0;;
esac
fi
if [ "$add_backports" = 1 ]; then
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
$SUDO apt-get update
fi
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
$SUDO apt-get update
fi
fi
$SUDO apt-get install -y --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
augeas_pkg=
if [ "$add_backports" != 0 ]; then
$SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
augeas_pkg=
fi
}
@@ -186,12 +233,12 @@ BootstrapDebCommon() {
AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse"
else
echo "No libaugeas0 version is available that's new enough to run the"
echo "Let's Encrypt apache plugin..."
echo "Certbot apache plugin..."
fi
# XXX add a case for ubuntu PPAs
fi
$SUDO apt-get install -y --no-install-recommends \
$SUDO apt-get install $YES_FLAG --no-install-recommends \
python \
python-dev \
$virtualenv \
@@ -212,9 +259,10 @@ BootstrapDebCommon() {
BootstrapRpmCommon() {
# Tested with:
# - Fedora 22, 23 (x64)
# - Fedora 20, 21, 22, 23 (x64)
# - Centos 7 (x64: on DigitalOcean droplet)
# - CentOS 7 Minimal install in a Hyper-V VM
# - CentOS 6 (EPEL must be installed manually)
if type dnf 2>/dev/null
then
@@ -228,54 +276,62 @@ BootstrapRpmCommon() {
exit 1
fi
pkgs="
gcc
dialog
augeas-libs
openssl
openssl-devel
libffi-devel
redhat-rpm-config
ca-certificates
"
# Some distros and older versions of current distros use a "python27"
# instead of "python" naming convention. Try both conventions.
if ! $SUDO $tool install -y \
python \
python-devel \
python-virtualenv \
python-tools \
python-pip
then
if ! $SUDO $tool install -y \
python27 \
python27-devel \
python27-virtualenv \
python27-tools \
python27-pip
then
echo "Could not install Python dependencies. Aborting bootstrap!"
exit 1
fi
if $SUDO $tool list python >/dev/null 2>&1; then
pkgs="$pkgs
python
python-devel
python-virtualenv
python-tools
python-pip
"
else
pkgs="$pkgs
python27
python27-devel
python27-virtualenv
python27-tools
python27-pip
"
fi
if ! $SUDO $tool install -y \
gcc \
dialog \
augeas-libs \
openssl \
openssl-devel \
libffi-devel \
redhat-rpm-config \
ca-certificates
then
echo "Could not install additional dependencies. Aborting bootstrap!"
exit 1
fi
if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then
if ! $SUDO $tool install -y mod_ssl
then
echo "Apache found, but mod_ssl could not be installed."
fi
pkgs="$pkgs
mod_ssl
"
fi
if [ "$ASSUME_YES" = 1 ]; then
yes_flag="-y"
fi
if ! $SUDO $tool install $yes_flag $pkgs; then
echo "Could not install OS dependencies. Aborting bootstrap!"
exit 1
fi
}
BootstrapSuseCommon() {
# SLE12 don't have python-virtualenv
$SUDO zypper -nq in -l \
if [ "$ASSUME_YES" = 1 ]; then
zypper_flags="-nq"
install_flags="-l"
fi
$SUDO zypper $zypper_flags in $install_flags \
python \
python-devel \
python-virtualenv \
@@ -310,8 +366,12 @@ BootstrapArchCommon() {
# pacman -T exits with 127 if there are missing dependencies
missing=$($SUDO pacman -T $deps) || true
if [ "$ASSUME_YES" = 1 ]; then
noconfirm="--noconfirm"
fi
if [ "$missing" ]; then
$SUDO pacman -S --needed $missing
$SUDO pacman -S --needed $missing $noconfirm
fi
}
@@ -426,7 +486,7 @@ Bootstrap() {
elif grep -iq "Amazon Linux" /etc/issue ; then
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
else
echo "Sorry, I don't know how to bootstrap Let's Encrypt on your operating system!"
echo "Sorry, I don't know how to bootstrap Certbot on your operating system!"
echo
echo "You will need to bootstrap, configure virtualenv, and run pip install manually."
echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites"
@@ -446,7 +506,8 @@ if [ "$1" = "--le-auto-phase2" ]; then
shift 1 # the --le-auto-phase2 arg
if [ -f "$VENV_BIN/letsencrypt" ]; then
# --version output ran through grep due to python-cryptography DeprecationWarnings
INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep ^letsencrypt | cut -d " " -f 2)
# 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)
else
INSTALLED_VERSION="none"
fi
@@ -465,8 +526,8 @@ if [ "$1" = "--le-auto-phase2" ]; then
# There is no $ interpolation due to quotes on starting heredoc delimiter.
# -------------------------------------------------------------------------
cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt"
# This is the flattened list of packages letsencrypt-auto installs. To generate
# this, do `pip install --no-cache-dir -e acme -e . -e letsencrypt-apache`, and
# This is the flattened list of packages certbot-auto installs. To generate
# this, do `pip install --no-cache-dir -e acme -e . -e certbot-apache`, and
# then use `hashin` or a more secure method to gather the hashes.
argparse==1.4.0 \
@@ -645,15 +706,21 @@ mock==1.0.1 \
# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE.
acme==0.5.0 \
--hash=sha256:ceb4127c13213f0006a564be82176b968c6b374d20d9fc78555d0658a252b275 \
--hash=sha256:0605c63c656d33c883a05675f5db9cfb85d503f2771c885031800e0da7631abd
letsencrypt==0.5.0 \
--hash=sha256:f90f883e99cdbdf8142335bdbf4f74a8af143ee4b4ec60fb49c6e47418c1114c \
--hash=sha256:e38a2b70b82be79bc195307652244a3e012ec73d897d4dbd3f80cf698496d15a
letsencrypt-apache==0.5.0 \
--hash=sha256:a767882164a7b09d9c12c80684a28a782135fdaf35654ef5a02c0b7b1d27ab8d \
--hash=sha256:c20e7b9c517aa4a7d70e6bd9382da7259f00bc191b9e60d8e312e48837a00c41
acme==0.6.0 \
--hash=sha256:cbe4e7a340a19725a8740ed86e30abdbe18fc22c4c6022b7a8e56642d502bcc3 \
--hash=sha256:ec4e6009dfbd629b58473eb06bbebfd9fb2a79fc8831c149e9205bc38a98ecc6
certbot==0.6.0 \
--hash=sha256:a893632d228864b0a751db9f3fdd93439ed34b988ea21b64fb0f0fa2ceded6a2 \
--hash=sha256:80b0b7dc5afeec2816ef638a61e7c628d73cd72666eebf4984be426d1c2b492d
certbot-apache==0.6.0 \
--hash=sha256:0ab077f0913b81ed5c1b141c3a7c4c0228ef3738d8d61a93db794d9a80718d43 \
--hash=sha256:1cfbe751209079a803758f472200816fac559f2a36fdd582d25e3ba5601423a1
letsencrypt==0.6.0 \
--hash=sha256:93196c7dcd57272a753e525d145c5a9987c8968c22ec954bcf83dcc9d2499a76 \
--hash=sha256:a16d6c395f1bf5fd61a28ef83dc78f42dbecbad9d00be6236f2ad8915645c154
letsencrypt-apache==0.6.0 \
--hash=sha256:02fadc52a0796e53978c508beec9c53e1fc047660240832b9bde5d53ab3a1379 \
--hash=sha256:1c5522d94d7750bdb9bfa6201d2c263e914f662c9d0079e673167233cf4364f1
UNLIKELY_EOF
# -------------------------------------------------------------------------
@@ -823,18 +890,30 @@ UNLIKELY_EOF
fi
echo "Installation succeeded."
fi
echo "Requesting root privileges to run letsencrypt..."
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
$SUDO "$VENV_BIN/letsencrypt" "$@"
echo "Requesting root privileges to run certbot..."
if [ -z "$SUDO_ENV" ] ; then
# SUDO is su wrapper / noop
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
$SUDO "$VENV_BIN/letsencrypt" "$@"
else
# sudo
echo " " $SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
$SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
fi
else
# Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke.
# Phase 1: Upgrade certbot-auto if neceesary, then self-invoke.
#
# Each phase checks the version of only the thing it is responsible for
# upgrading. Phase 1 checks the version of the latest release of
# letsencrypt-auto (which is always the same as that of the letsencrypt
# package). Phase 2 checks the version of the locally installed letsencrypt.
# certbot-auto (which is always the same as that of the certbot
# 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
fi
# If it looks like we've never bootstrapped before, bootstrap:
Bootstrap
fi
@@ -953,7 +1032,7 @@ def verified_new_le_auto(get, tag, temp_dir):
stderr=dev_null)
except CalledProcessError as exc:
raise ExpectedError("Couldn't verify signature of downloaded "
"letsencrypt-auto.", exc)
"certbot-auto.", exc)
def main():
@@ -978,29 +1057,27 @@ if __name__ == '__main__':
UNLIKELY_EOF
# ---------------------------------------------------------------------------
DeterminePythonVersion
REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version`
if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then
echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
if ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
echo "WARNING: unable to check for updates."
elif [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then
echo "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
# Now we drop into Python so we don't have to install even more
# dependencies (curl, etc.), for better flow control, and for the option of
# future Windows compatibility.
"$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION"
# Install new copy of letsencrypt-auto.
# Install new copy of certbot-auto.
# TODO: Deal with quotes in pathnames.
echo "Replacing letsencrypt-auto..."
echo "Replacing certbot-auto..."
# Clone permissions with cp. chmod and chown don't have a --reference
# option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD:
echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
$SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
$SUDO 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.
echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
$SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
# TODO: Clean up temp dir safely, even if it has quotes in its path.
rm -rf "$TEMP_DIR"
+11
View File
@@ -0,0 +1,11 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABAgAGBQJXM9ZDAAoJEE0XyZXNl3XyzGkH/2KeR0jYxXKlvwfCkxU6hSC0
eXcxZVQk59hCSvkNGE6Mj6rwQcyjSqmRp14MaJpq7NZADN6F+HWb6VB/Wq6moMQs
PJtthqwhF767Qg+Py9Hp6XmlKscjXB6AKCVxq5TBwEIOTtj0rhQRLF9/+GW6jFuf
kT6aUcDWNjOyWWUtp9vOVprDtegrltp0/2DNitlvPu263pKC+7I3GyLTq4fKP4EE
auZSAhFry9SNR3Usf2wD3kzhvLSrT3h9Yh5oA04oaX9H6e86EHwt6RJJRHpg8s6b
e0CBIIuaRJEmdiMUWlV/gAfH6M2PbG1wtJdxc0ThNEoWAjTsopr61BoHJ3cpCy4=
=+e7/
-----END PGP SIGNATURE-----
+173 -96
View File
@@ -1,6 +1,6 @@
#!/bin/sh
#
# Download and run the latest release version of the Let's Encrypt client.
# Download and run the latest release version of the Certbot client.
#
# NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING
#
@@ -19,11 +19,36 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share}
VENV_NAME="letsencrypt"
VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"}
VENV_BIN="$VENV_PATH/bin"
LE_AUTO_VERSION="0.6.0.dev0"
LE_AUTO_VERSION="0.7.0.dev0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
to both this script and certbot will be downloaded and installed. After
ensuring you have the latest versions installed, certbot will be invoked with
all arguments you have provided.
Help for certbot itself cannot be provided until it is installed.
--debug attempt experimental installation
-h, --help print this help
-n, --non-interactive, --noninteractive run without asking for user input
--no-self-upgrade do not download updates
--os-packages-only install OS dependencies and exit
-v, --verbose provide more output
All arguments are accepted and forwarded to the Certbot client when run."
while getopts ":hnv" arg; do
case $arg in
h)
HELP=1;;
n)
ASSUME_YES=1;;
v)
VERBOSE=1;;
esac
done
# This script takes the same arguments as the main letsencrypt program, but it
# additionally responds to --verbose (more output) and --debug (allow support
# for experimental platforms)
for arg in "$@" ; do
case "$arg" in
--debug)
@@ -34,25 +59,26 @@ for arg in "$@" ; do
# Do not upgrade this script (also prevents client upgrades, because each
# copy of the script pins a hash of the python client)
NO_SELF_UPGRADE=1;;
--help)
HELP=1;;
--noninteractive|--non-interactive)
ASSUME_YES=1;;
--verbose)
VERBOSE=1;;
[!-]*|-*[!v]*|-)
# Anything that isn't -v, -vv, etc.: that is, anything that does not
# start with a -, contains anything that's not a v, or is just "-"
;;
*) # -v+ remains.
VERBOSE=1;;
esac
done
# letsencrypt-auto needs root access to bootstrap OS dependencies, and
# letsencrypt itself needs root access for almost all modes of operation
# 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`
SUDO_ENV=""
export CERTBOT_AUTO="$0"
if test "`id -u`" -ne "0" ; then
if command -v sudo 1>/dev/null 2>&1; then
SUDO=sudo
SUDO_ENV="CERTBOT_AUTO=$0"
else
echo \"sudo\" is not available, will use \"su\" for installation steps...
# Because the parameters in `su -c` has to be a string,
@@ -81,6 +107,12 @@ else
SUDO=
fi
if [ $BASENAME = "letsencrypt-auto" ]; then
# letsencrypt-auto does not respect --help or --yes for backwards compatibility
ASSUME_YES=1
HELP=0
fi
ExperimentalBootstrap() {
# Arguments: Platform name, bootstrap function name
if [ "$DEBUG" = 1 ]; then
@@ -151,30 +183,45 @@ BootstrapDebCommon() {
augeas_pkg="libaugeas0 augeas-lenses"
AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2`
if [ "$ASSUME_YES" = 1 ]; then
YES_FLAG="-y"
fi
AddBackportRepo() {
# ARGS:
BACKPORT_NAME="$1"
BACKPORT_SOURCELINE="$2"
echo "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME."
if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then
# This can theoretically error if sources.list.d is empty, but in that case we don't care.
if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then
/bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..."
sleep 1s
/bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..."
sleep 1s
/bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..."
sleep 1s
if echo $BACKPORT_NAME | grep -q wheezy ; then
/bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")'
if [ "$ASSUME_YES" = 1 ]; then
/bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..."
sleep 1s
/bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..."
sleep 1s
/bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..."
sleep 1s
add_backports=1
else
read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response
case $response in
[yY][eE][sS]|[yY]|"")
add_backports=1;;
*)
add_backports=0;;
esac
fi
if [ "$add_backports" = 1 ]; then
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
$SUDO apt-get update
fi
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
$SUDO apt-get update
fi
fi
$SUDO apt-get install -y --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
augeas_pkg=
if [ "$add_backports" != 0 ]; then
$SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
augeas_pkg=
fi
}
@@ -186,12 +233,12 @@ BootstrapDebCommon() {
AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse"
else
echo "No libaugeas0 version is available that's new enough to run the"
echo "Let's Encrypt apache plugin..."
echo "Certbot apache plugin..."
fi
# XXX add a case for ubuntu PPAs
fi
$SUDO apt-get install -y --no-install-recommends \
$SUDO apt-get install $YES_FLAG --no-install-recommends \
python \
python-dev \
$virtualenv \
@@ -212,9 +259,10 @@ BootstrapDebCommon() {
BootstrapRpmCommon() {
# Tested with:
# - Fedora 22, 23 (x64)
# - Fedora 20, 21, 22, 23 (x64)
# - Centos 7 (x64: on DigitalOcean droplet)
# - CentOS 7 Minimal install in a Hyper-V VM
# - CentOS 6 (EPEL must be installed manually)
if type dnf 2>/dev/null
then
@@ -228,54 +276,62 @@ BootstrapRpmCommon() {
exit 1
fi
pkgs="
gcc
dialog
augeas-libs
openssl
openssl-devel
libffi-devel
redhat-rpm-config
ca-certificates
"
# Some distros and older versions of current distros use a "python27"
# instead of "python" naming convention. Try both conventions.
if ! $SUDO $tool install -y \
python \
python-devel \
python-virtualenv \
python-tools \
python-pip
then
if ! $SUDO $tool install -y \
python27 \
python27-devel \
python27-virtualenv \
python27-tools \
python27-pip
then
echo "Could not install Python dependencies. Aborting bootstrap!"
exit 1
fi
if $SUDO $tool list python >/dev/null 2>&1; then
pkgs="$pkgs
python
python-devel
python-virtualenv
python-tools
python-pip
"
else
pkgs="$pkgs
python27
python27-devel
python27-virtualenv
python27-tools
python27-pip
"
fi
if ! $SUDO $tool install -y \
gcc \
dialog \
augeas-libs \
openssl \
openssl-devel \
libffi-devel \
redhat-rpm-config \
ca-certificates
then
echo "Could not install additional dependencies. Aborting bootstrap!"
exit 1
fi
if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then
if ! $SUDO $tool install -y mod_ssl
then
echo "Apache found, but mod_ssl could not be installed."
fi
pkgs="$pkgs
mod_ssl
"
fi
if [ "$ASSUME_YES" = 1 ]; then
yes_flag="-y"
fi
if ! $SUDO $tool install $yes_flag $pkgs; then
echo "Could not install OS dependencies. Aborting bootstrap!"
exit 1
fi
}
BootstrapSuseCommon() {
# SLE12 don't have python-virtualenv
$SUDO zypper -nq in -l \
if [ "$ASSUME_YES" = 1 ]; then
zypper_flags="-nq"
install_flags="-l"
fi
$SUDO zypper $zypper_flags in $install_flags \
python \
python-devel \
python-virtualenv \
@@ -310,8 +366,12 @@ BootstrapArchCommon() {
# pacman -T exits with 127 if there are missing dependencies
missing=$($SUDO pacman -T $deps) || true
if [ "$ASSUME_YES" = 1 ]; then
noconfirm="--noconfirm"
fi
if [ "$missing" ]; then
$SUDO pacman -S --needed $missing
$SUDO pacman -S --needed $missing $noconfirm
fi
}
@@ -426,7 +486,7 @@ Bootstrap() {
elif grep -iq "Amazon Linux" /etc/issue ; then
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
else
echo "Sorry, I don't know how to bootstrap Let's Encrypt on your operating system!"
echo "Sorry, I don't know how to bootstrap Certbot on your operating system!"
echo
echo "You will need to bootstrap, configure virtualenv, and run pip install manually."
echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites"
@@ -446,7 +506,8 @@ if [ "$1" = "--le-auto-phase2" ]; then
shift 1 # the --le-auto-phase2 arg
if [ -f "$VENV_BIN/letsencrypt" ]; then
# --version output ran through grep due to python-cryptography DeprecationWarnings
INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep ^letsencrypt | cut -d " " -f 2)
# 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)
else
INSTALLED_VERSION="none"
fi
@@ -465,8 +526,8 @@ if [ "$1" = "--le-auto-phase2" ]; then
# There is no $ interpolation due to quotes on starting heredoc delimiter.
# -------------------------------------------------------------------------
cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt"
# This is the flattened list of packages letsencrypt-auto installs. To generate
# this, do `pip install --no-cache-dir -e acme -e . -e letsencrypt-apache`, and
# This is the flattened list of packages certbot-auto installs. To generate
# this, do `pip install --no-cache-dir -e acme -e . -e certbot-apache`, and
# then use `hashin` or a more secure method to gather the hashes.
argparse==1.4.0 \
@@ -645,15 +706,21 @@ mock==1.0.1 \
# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE.
acme==0.5.0 \
--hash=sha256:ceb4127c13213f0006a564be82176b968c6b374d20d9fc78555d0658a252b275 \
--hash=sha256:0605c63c656d33c883a05675f5db9cfb85d503f2771c885031800e0da7631abd
letsencrypt==0.5.0 \
--hash=sha256:f90f883e99cdbdf8142335bdbf4f74a8af143ee4b4ec60fb49c6e47418c1114c \
--hash=sha256:e38a2b70b82be79bc195307652244a3e012ec73d897d4dbd3f80cf698496d15a
letsencrypt-apache==0.5.0 \
--hash=sha256:a767882164a7b09d9c12c80684a28a782135fdaf35654ef5a02c0b7b1d27ab8d \
--hash=sha256:c20e7b9c517aa4a7d70e6bd9382da7259f00bc191b9e60d8e312e48837a00c41
acme==0.6.0 \
--hash=sha256:cbe4e7a340a19725a8740ed86e30abdbe18fc22c4c6022b7a8e56642d502bcc3 \
--hash=sha256:ec4e6009dfbd629b58473eb06bbebfd9fb2a79fc8831c149e9205bc38a98ecc6
certbot==0.6.0 \
--hash=sha256:a893632d228864b0a751db9f3fdd93439ed34b988ea21b64fb0f0fa2ceded6a2 \
--hash=sha256:80b0b7dc5afeec2816ef638a61e7c628d73cd72666eebf4984be426d1c2b492d
certbot-apache==0.6.0 \
--hash=sha256:0ab077f0913b81ed5c1b141c3a7c4c0228ef3738d8d61a93db794d9a80718d43 \
--hash=sha256:1cfbe751209079a803758f472200816fac559f2a36fdd582d25e3ba5601423a1
letsencrypt==0.6.0 \
--hash=sha256:93196c7dcd57272a753e525d145c5a9987c8968c22ec954bcf83dcc9d2499a76 \
--hash=sha256:a16d6c395f1bf5fd61a28ef83dc78f42dbecbad9d00be6236f2ad8915645c154
letsencrypt-apache==0.6.0 \
--hash=sha256:02fadc52a0796e53978c508beec9c53e1fc047660240832b9bde5d53ab3a1379 \
--hash=sha256:1c5522d94d7750bdb9bfa6201d2c263e914f662c9d0079e673167233cf4364f1
UNLIKELY_EOF
# -------------------------------------------------------------------------
@@ -823,18 +890,30 @@ UNLIKELY_EOF
fi
echo "Installation succeeded."
fi
echo "Requesting root privileges to run letsencrypt..."
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
$SUDO "$VENV_BIN/letsencrypt" "$@"
echo "Requesting root privileges to run certbot..."
if [ -z "$SUDO_ENV" ] ; then
# SUDO is su wrapper / noop
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
$SUDO "$VENV_BIN/letsencrypt" "$@"
else
# sudo
echo " " $SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
$SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
fi
else
# Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke.
# Phase 1: Upgrade certbot-auto if neceesary, then self-invoke.
#
# Each phase checks the version of only the thing it is responsible for
# upgrading. Phase 1 checks the version of the latest release of
# letsencrypt-auto (which is always the same as that of the letsencrypt
# package). Phase 2 checks the version of the locally installed letsencrypt.
# certbot-auto (which is always the same as that of the certbot
# 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
fi
# If it looks like we've never bootstrapped before, bootstrap:
Bootstrap
fi
@@ -953,7 +1032,7 @@ def verified_new_le_auto(get, tag, temp_dir):
stderr=dev_null)
except CalledProcessError as exc:
raise ExpectedError("Couldn't verify signature of downloaded "
"letsencrypt-auto.", exc)
"certbot-auto.", exc)
def main():
@@ -978,29 +1057,27 @@ if __name__ == '__main__':
UNLIKELY_EOF
# ---------------------------------------------------------------------------
DeterminePythonVersion
REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version`
if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then
echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
if ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
echo "WARNING: unable to check for updates."
elif [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then
echo "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
# Now we drop into Python so we don't have to install even more
# dependencies (curl, etc.), for better flow control, and for the option of
# future Windows compatibility.
"$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION"
# Install new copy of letsencrypt-auto.
# Install new copy of certbot-auto.
# TODO: Deal with quotes in pathnames.
echo "Replacing letsencrypt-auto..."
echo "Replacing certbot-auto..."
# Clone permissions with cp. chmod and chown don't have a --reference
# option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD:
echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
$SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
$SUDO 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.
echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
$SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
# TODO: Clean up temp dir safely, even if it has quotes in its path.
rm -rf "$TEMP_DIR"
Binary file not shown.
@@ -20,10 +20,35 @@ VENV_NAME="letsencrypt"
VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"}
VENV_BIN="$VENV_PATH/bin"
LE_AUTO_VERSION="{{ LE_AUTO_VERSION }}"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
to both this script and certbot will be downloaded and installed. After
ensuring you have the latest versions installed, certbot will be invoked with
all arguments you have provided.
Help for certbot itself cannot be provided until it is installed.
--debug attempt experimental installation
-h, --help print this help
-n, --non-interactive, --noninteractive run without asking for user input
--no-self-upgrade do not download updates
--os-packages-only install OS dependencies and exit
-v, --verbose provide more output
All arguments are accepted and forwarded to the Certbot client when run."
while getopts ":hnv" arg; do
case $arg in
h)
HELP=1;;
n)
ASSUME_YES=1;;
v)
VERBOSE=1;;
esac
done
# This script takes the same arguments as the main letsencrypt program, but it
# additionally responds to --verbose (more output) and --debug (allow support
# for experimental platforms)
for arg in "$@" ; do
case "$arg" in
--debug)
@@ -34,25 +59,26 @@ for arg in "$@" ; do
# Do not upgrade this script (also prevents client upgrades, because each
# copy of the script pins a hash of the python client)
NO_SELF_UPGRADE=1;;
--help)
HELP=1;;
--noninteractive|--non-interactive)
ASSUME_YES=1;;
--verbose)
VERBOSE=1;;
[!-]*|-*[!v]*|-)
# Anything that isn't -v, -vv, etc.: that is, anything that does not
# start with a -, contains anything that's not a v, or is just "-"
;;
*) # -v+ remains.
VERBOSE=1;;
esac
done
# letsencrypt-auto needs root access to bootstrap OS dependencies, and
# 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`
SUDO_ENV=""
export CERTBOT_AUTO="$0"
if test "`id -u`" -ne "0" ; then
if command -v sudo 1>/dev/null 2>&1; then
SUDO=sudo
SUDO_ENV="CERTBOT_AUTO=$0"
else
echo \"sudo\" is not available, will use \"su\" for installation steps...
# Because the parameters in `su -c` has to be a string,
@@ -81,6 +107,12 @@ else
SUDO=
fi
if [ $BASENAME = "letsencrypt-auto" ]; then
# letsencrypt-auto does not respect --help or --yes for backwards compatibility
ASSUME_YES=1
HELP=0
fi
ExperimentalBootstrap() {
# Arguments: Platform name, bootstrap function name
if [ "$DEBUG" = 1 ]; then
@@ -177,7 +209,8 @@ if [ "$1" = "--le-auto-phase2" ]; then
shift 1 # the --le-auto-phase2 arg
if [ -f "$VENV_BIN/letsencrypt" ]; then
# --version output ran through grep due to python-cryptography DeprecationWarnings
INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep ^letsencrypt | cut -d " " -f 2)
# 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)
else
INSTALLED_VERSION="none"
fi
@@ -220,17 +253,29 @@ UNLIKELY_EOF
echo "Installation succeeded."
fi
echo "Requesting root privileges to run certbot..."
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
$SUDO "$VENV_BIN/letsencrypt" "$@"
if [ -z "$SUDO_ENV" ] ; then
# SUDO is su wrapper / noop
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
$SUDO "$VENV_BIN/letsencrypt" "$@"
else
# sudo
echo " " $SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
$SUDO "$SUDO_ENV" "$VENV_BIN/letsencrypt" "$@"
fi
else
# Phase 1: Upgrade letsencrypt-auto if neceesary, then self-invoke.
# Phase 1: Upgrade certbot-auto if neceesary, then self-invoke.
#
# Each phase checks the version of only the thing it is responsible for
# upgrading. Phase 1 checks the version of the latest release of
# letsencrypt-auto (which is always the same as that of the certbot
# certbot-auto (which is always the same as that of the certbot
# 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
fi
# If it looks like we've never bootstrapped before, bootstrap:
Bootstrap
fi
@@ -248,29 +293,27 @@ else
UNLIKELY_EOF
# ---------------------------------------------------------------------------
DeterminePythonVersion
REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version`
if [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then
echo "Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
if ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
echo "WARNING: unable to check for updates."
elif [ "$LE_AUTO_VERSION" != "$REMOTE_VERSION" ]; then
echo "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
# Now we drop into Python so we don't have to install even more
# dependencies (curl, etc.), for better flow control, and for the option of
# future Windows compatibility.
"$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION"
# Install new copy of letsencrypt-auto.
# Install new copy of certbot-auto.
# TODO: Deal with quotes in pathnames.
echo "Replacing letsencrypt-auto..."
echo "Replacing certbot-auto..."
# Clone permissions with cp. chmod and chown don't have a --reference
# option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD:
echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
$SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
$SUDO 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.
echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
$SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
# TODO: Clean up temp dir safely, even if it has quotes in its path.
rm -rf "$TEMP_DIR"
@@ -21,7 +21,11 @@ BootstrapArchCommon() {
# pacman -T exits with 127 if there are missing dependencies
missing=$($SUDO pacman -T $deps) || true
if [ "$ASSUME_YES" = 1 ]; then
noconfirm="--noconfirm"
fi
if [ "$missing" ]; then
$SUDO pacman -S --needed $missing
$SUDO pacman -S --needed $missing $noconfirm
fi
}
@@ -34,30 +34,45 @@ BootstrapDebCommon() {
augeas_pkg="libaugeas0 augeas-lenses"
AUGVERSION=`apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2`
if [ "$ASSUME_YES" = 1 ]; then
YES_FLAG="-y"
fi
AddBackportRepo() {
# ARGS:
BACKPORT_NAME="$1"
BACKPORT_SOURCELINE="$2"
echo "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME."
if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then
# This can theoretically error if sources.list.d is empty, but in that case we don't care.
if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then
/bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..."
sleep 1s
/bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..."
sleep 1s
/bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..."
sleep 1s
if echo $BACKPORT_NAME | grep -q wheezy ; then
/bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")'
if [ "$ASSUME_YES" = 1 ]; then
/bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..."
sleep 1s
/bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..."
sleep 1s
/bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..."
sleep 1s
add_backports=1
else
read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response
case $response in
[yY][eE][sS]|[yY]|"")
add_backports=1;;
*)
add_backports=0;;
esac
fi
if [ "$add_backports" = 1 ]; then
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
$SUDO apt-get update
fi
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
$SUDO apt-get update
fi
fi
$SUDO apt-get install -y --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
augeas_pkg=
if [ "$add_backports" != 0 ]; then
$SUDO apt-get install $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
augeas_pkg=
fi
}
@@ -74,7 +89,7 @@ BootstrapDebCommon() {
# XXX add a case for ubuntu PPAs
fi
$SUDO apt-get install -y --no-install-recommends \
$SUDO apt-get install $YES_FLAG --no-install-recommends \
python \
python-dev \
$virtualenv \
@@ -1,8 +1,9 @@
BootstrapRpmCommon() {
# Tested with:
# - Fedora 22, 23 (x64)
# - Fedora 20, 21, 22, 23 (x64)
# - Centos 7 (x64: on DigitalOcean droplet)
# - CentOS 7 Minimal install in a Hyper-V VM
# - CentOS 6 (EPEL must be installed manually)
if type dnf 2>/dev/null
then
@@ -16,46 +17,49 @@ BootstrapRpmCommon() {
exit 1
fi
pkgs="
gcc
dialog
augeas-libs
openssl
openssl-devel
libffi-devel
redhat-rpm-config
ca-certificates
"
# Some distros and older versions of current distros use a "python27"
# instead of "python" naming convention. Try both conventions.
if ! $SUDO $tool install -y \
python \
python-devel \
python-virtualenv \
python-tools \
python-pip
then
if ! $SUDO $tool install -y \
python27 \
python27-devel \
python27-virtualenv \
python27-tools \
python27-pip
then
echo "Could not install Python dependencies. Aborting bootstrap!"
exit 1
fi
if $SUDO $tool list python >/dev/null 2>&1; then
pkgs="$pkgs
python
python-devel
python-virtualenv
python-tools
python-pip
"
else
pkgs="$pkgs
python27
python27-devel
python27-virtualenv
python27-tools
python27-pip
"
fi
if ! $SUDO $tool install -y \
gcc \
dialog \
augeas-libs \
openssl \
openssl-devel \
libffi-devel \
redhat-rpm-config \
ca-certificates
then
echo "Could not install additional dependencies. Aborting bootstrap!"
exit 1
fi
if $SUDO $tool list installed "httpd" >/dev/null 2>&1; then
if ! $SUDO $tool install -y mod_ssl
then
echo "Apache found, but mod_ssl could not be installed."
fi
pkgs="$pkgs
mod_ssl
"
fi
if [ "$ASSUME_YES" = 1 ]; then
yes_flag="-y"
fi
if ! $SUDO $tool install $yes_flag $pkgs; then
echo "Could not install OS dependencies. Aborting bootstrap!"
exit 1
fi
}
@@ -1,7 +1,12 @@
BootstrapSuseCommon() {
# SLE12 don't have python-virtualenv
$SUDO zypper -nq in -l \
if [ "$ASSUME_YES" = 1 ]; then
zypper_flags="-nq"
install_flags="-l"
fi
$SUDO zypper $zypper_flags in $install_flags \
python \
python-devel \
python-virtualenv \
+1 -1
View File
@@ -103,7 +103,7 @@ def verified_new_le_auto(get, tag, temp_dir):
stderr=dev_null)
except CalledProcessError as exc:
raise ExpectedError("Couldn't verify signature of downloaded "
"letsencrypt-auto.", exc)
"certbot-auto.", exc)
def main():
@@ -1,4 +1,4 @@
# This is the flattened list of packages letsencrypt-auto installs. To generate
# This is the flattened list of packages certbot-auto installs. To generate
# this, do `pip install --no-cache-dir -e acme -e . -e certbot-apache`, and
# then use `hashin` or a more secure method to gather the hashes.
@@ -178,12 +178,18 @@ mock==1.0.1 \
# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE.
acme==0.5.0 \
--hash=sha256:ceb4127c13213f0006a564be82176b968c6b374d20d9fc78555d0658a252b275 \
--hash=sha256:0605c63c656d33c883a05675f5db9cfb85d503f2771c885031800e0da7631abd
letsencrypt==0.5.0 \
--hash=sha256:f90f883e99cdbdf8142335bdbf4f74a8af143ee4b4ec60fb49c6e47418c1114c \
--hash=sha256:e38a2b70b82be79bc195307652244a3e012ec73d897d4dbd3f80cf698496d15a
letsencrypt-apache==0.5.0 \
--hash=sha256:a767882164a7b09d9c12c80684a28a782135fdaf35654ef5a02c0b7b1d27ab8d \
--hash=sha256:c20e7b9c517aa4a7d70e6bd9382da7259f00bc191b9e60d8e312e48837a00c41
acme==0.6.0 \
--hash=sha256:cbe4e7a340a19725a8740ed86e30abdbe18fc22c4c6022b7a8e56642d502bcc3 \
--hash=sha256:ec4e6009dfbd629b58473eb06bbebfd9fb2a79fc8831c149e9205bc38a98ecc6
certbot==0.6.0 \
--hash=sha256:a893632d228864b0a751db9f3fdd93439ed34b988ea21b64fb0f0fa2ceded6a2 \
--hash=sha256:80b0b7dc5afeec2816ef638a61e7c628d73cd72666eebf4984be426d1c2b492d
certbot-apache==0.6.0 \
--hash=sha256:0ab077f0913b81ed5c1b141c3a7c4c0228ef3738d8d61a93db794d9a80718d43 \
--hash=sha256:1cfbe751209079a803758f472200816fac559f2a36fdd582d25e3ba5601423a1
letsencrypt==0.6.0 \
--hash=sha256:93196c7dcd57272a753e525d145c5a9987c8968c22ec954bcf83dcc9d2499a76 \
--hash=sha256:a16d6c395f1bf5fd61a28ef83dc78f42dbecbad9d00be6236f2ad8915645c154
letsencrypt-apache==0.6.0 \
--hash=sha256:02fadc52a0796e53978c508beec9c53e1fc047660240832b9bde5d53ab3a1379 \
--hash=sha256:1c5522d94d7750bdb9bfa6201d2c263e914f662c9d0079e673167233cf4364f1
+6 -6
View File
@@ -231,7 +231,7 @@ class AutoTests(TestCase):
* The OpenSSL sig mismatches.
For tests which get to the end, we run merely ``letsencrypt --version``.
The functioning of the rest of the letsencrypt script is covered by other
The functioning of the rest of the certbot script is covered by other
test suites.
"""
@@ -277,7 +277,7 @@ class AutoTests(TestCase):
ok_(re.match(r'letsencrypt \d+\.\d+\.\d+',
err.strip().splitlines()[-1]))
# Make a few assertions to test the validity of the next tests:
self.assertIn('Upgrading letsencrypt-auto ', out)
self.assertIn('Upgrading certbot-auto ', out)
self.assertIn('Creating virtual environment...', out)
# Now we have le-auto 99.9.9 and LE 99.9.9 installed. This
@@ -286,14 +286,14 @@ class AutoTests(TestCase):
# Test when neither phase-1 upgrade nor phase-2 upgrade is
# needed (probably a common case):
out, err = run_letsencrypt_auto()
self.assertNotIn('Upgrading letsencrypt-auto ', out)
self.assertNotIn('Upgrading certbot-auto ', out)
self.assertNotIn('Creating virtual environment...', out)
# Test when a phase-1 upgrade is not needed but a phase-2
# upgrade is:
set_le_script_version(venv_dir, '0.0.1')
out, err = run_letsencrypt_auto()
self.assertNotIn('Upgrading letsencrypt-auto ', out)
self.assertNotIn('Upgrading certbot-auto ', out)
self.assertIn('Creating virtual environment...', out)
def test_openssl_failure(self):
@@ -312,10 +312,10 @@ class AutoTests(TestCase):
except CalledProcessError as exc:
eq_(exc.returncode, 1)
self.assertIn("Couldn't verify signature of downloaded "
"letsencrypt-auto.",
"certbot-auto.",
exc.output)
else:
self.fail('Signature check on letsencrypt-auto erroneously passed.')
self.fail('Signature check on certbot-auto erroneously passed.')
def test_pip_failure(self):
"""Make sure pip stops us if there is a hash mismatch."""
+1 -1
View File
@@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__))
readme = read_file(os.path.join(here, 'README.rst'))
version = '0.6.0.dev0'
version = '0.7.0.dev0'
# This package is a simple shim around certbot-nginx
+1 -1
View File
@@ -20,7 +20,7 @@ readme = read_file(os.path.join(here, 'README.rst'))
install_requires = ['certbot']
version = '0.6.0.dev0'
version = '0.7.0.dev0'
setup(
+1 -1
View File
@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.6.0.dev0'
version = '0.7.0.dev0'
install_requires = [
'setuptools', # pkg_resources
+1 -1
View File
@@ -16,7 +16,7 @@ here = os.path.abspath(os.path.dirname(__file__))
readme = read_file(os.path.join(here, 'README.rst'))
version = '0.6.0.dev0'
version = '0.7.0.dev0'
# This package is a simple shim around letshelp-certbot
+11 -4
View File
@@ -45,7 +45,7 @@ export GPG_TTY=$(tty)
PORT=${PORT:-1234}
# subpackages to be released
SUBPKGS=${SUBPKGS:-"acme certbot-apache certbot-nginx letshelp-certbot"}
SUBPKGS=${SUBPKGS:-"acme certbot-apache certbot-nginx letshelp-certbot letsencrypt letsencrypt-apache letsencrypt-nginx letshelp-letsencrypt"}
subpkgs_modules="$(echo $SUBPKGS | sed s/-/_/g)"
# certbot_compatibility_test is not packaged because:
# - it is not meant to be used by anyone else than Certbot devs
@@ -162,12 +162,12 @@ done
deactivate
# pin pip hashes of the things we just built
for pkg in acme certbot certbot-apache ; do
for pkg in acme certbot certbot-apache letsencrypt letsencrypt-apache ; do
echo $pkg==$version \\
pip hash dist."$version/$pkg"/*.{whl,gz} | grep "^--hash" | python2 -c 'from sys import stdin; input = stdin.read(); print " ", input.replace("\n--hash", " \\\n --hash"),'
done > /tmp/hashes.$$
if ! wc -l /tmp/hashes.$$ | grep -qE "^\s*9 " ; then
if ! wc -l /tmp/hashes.$$ | grep -qE "^\s*15 " ; then
echo Unexpected pip hash output
exit 1
fi
@@ -187,10 +187,17 @@ while ! openssl dgst -sha256 -verify $RELEASE_OPENSSL_PUBKEY -signature \
read -p "Please correctly sign letsencrypt-auto with offline-signrequest.sh"
done
# This signature is not quite as strong, but easier for people to verify out of band
gpg -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign letsencrypt-auto-source/letsencrypt-auto
# We can't rename the openssl letsencrypt-auto.sig for compatibility reasons,
# but we can use the right name for cerbot-auto.asc from day one
mv letsencrypt-auto-source/letsencrypt-auto.asc letsencrypt-auto-source/certbot-auto.asc
# copy leauto to the root, overwriting the previous release version
cp -p letsencrypt-auto-source/letsencrypt-auto certbot-auto
cp -p letsencrypt-auto-source/letsencrypt-auto letsencrypt-auto
git add letsencrypt-auto letsencrypt-auto-source
git add certbot-auto letsencrypt-auto letsencrypt-auto-source
git diff --cached
git commit --gpg-sign="$RELEASE_GPG_KEY" -m "Release $version"
git tag --local-user "$RELEASE_GPG_KEY" --sign --message "Release $version" "$tag"