mirror of
https://github.com/certbot/certbot.git
synced 2026-01-26 07:41:33 +03:00
282 lines
11 KiB
Bash
Executable File
282 lines
11 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# Download and run the latest release version of the Certbot client.
|
|
#
|
|
# NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING
|
|
#
|
|
# IF YOU WANT TO EDIT IT LOCALLY, *ALWAYS* RUN YOUR COPY WITH THE
|
|
# "--no-self-upgrade" FLAG
|
|
#
|
|
# IF YOU WANT TO SEND PULL REQUESTS, THE REAL SOURCE FOR THIS FILE IS
|
|
# letsencrypt-auto-source/letsencrypt-auto.template AND
|
|
# letsencrypt-auto-source/pieces/bootstrappers/*
|
|
|
|
set -e # Work even if somebody does "sh thisscript.sh".
|
|
|
|
# Note: you can set XDG_DATA_HOME or VENV_PATH before running this script,
|
|
# if you want to change where the virtual environment will be installed
|
|
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="{{ LE_AUTO_VERSION }}"
|
|
|
|
# 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)
|
|
DEBUG=1;;
|
|
--os-packages-only)
|
|
OS_PACKAGES_ONLY=1;;
|
|
--no-self-upgrade)
|
|
# 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;;
|
|
--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 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`
|
|
if test "`id -u`" -ne "0" ; then
|
|
if command -v sudo 1>/dev/null 2>&1; then
|
|
SUDO=sudo
|
|
else
|
|
echo \"sudo\" is not available, will use \"su\" for installation steps...
|
|
# Because the parameters in `su -c` has to be a string,
|
|
# we need properly escape it
|
|
su_sudo() {
|
|
args=""
|
|
# This `while` loop iterates over all parameters given to this function.
|
|
# For each parameter, all `'` will be replace by `'"'"'`, and the escaped string
|
|
# will be wrapped in a pair of `'`, then appended to `$args` string
|
|
# For example, `echo "It's only 1\$\!"` will be escaped to:
|
|
# 'echo' 'It'"'"'s only 1$!'
|
|
# │ │└┼┘│
|
|
# │ │ │ └── `'s only 1$!'` the literal string
|
|
# │ │ └── `\"'\"` is a single quote (as a string)
|
|
# │ └── `'It'`, to be concatenated with the strings following it
|
|
# └── `echo` wrapped in a pair of `'`, it's totally fine for the shell command itself
|
|
while [ $# -ne 0 ]; do
|
|
args="$args'$(printf "%s" "$1" | sed -e "s/'/'\"'\"'/g")' "
|
|
shift
|
|
done
|
|
su root -c "$args"
|
|
}
|
|
SUDO=su_sudo
|
|
fi
|
|
else
|
|
SUDO=
|
|
fi
|
|
|
|
ExperimentalBootstrap() {
|
|
# Arguments: Platform name, bootstrap function name
|
|
if [ "$DEBUG" = 1 ]; then
|
|
if [ "$2" != "" ]; then
|
|
echo "Bootstrapping dependencies via $1..."
|
|
$2
|
|
fi
|
|
else
|
|
echo "WARNING: $1 support is very experimental at present..."
|
|
echo "if you would like to work on improving it, please ensure you have backups"
|
|
echo "and then run this script again with the --debug flag!"
|
|
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.
|
|
command -v "$LE_PYTHON" > /dev/null && break
|
|
done
|
|
if [ "$?" != "0" ]; then
|
|
echo "Cannot find any Pythons; please install one!"
|
|
exit 1
|
|
fi
|
|
export LE_PYTHON
|
|
|
|
PYVER=`"$LE_PYTHON" -V 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed 's/\.//'`
|
|
if [ "$PYVER" -lt 26 ]; then
|
|
echo "You have an ancient version of Python entombed in your operating system..."
|
|
echo "This isn't going to work; you'll need at least version 2.6."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
{{ bootstrappers/deb_common.sh }}
|
|
{{ bootstrappers/rpm_common.sh }}
|
|
{{ bootstrappers/suse_common.sh }}
|
|
{{ bootstrappers/arch_common.sh }}
|
|
{{ bootstrappers/gentoo_common.sh }}
|
|
{{ bootstrappers/free_bsd.sh }}
|
|
{{ bootstrappers/mac.sh }}
|
|
|
|
# Install required OS packages:
|
|
Bootstrap() {
|
|
if [ -f /etc/debian_version ]; then
|
|
echo "Bootstrapping dependencies for Debian-based OSes..."
|
|
BootstrapDebCommon
|
|
elif [ -f /etc/redhat-release ]; then
|
|
echo "Bootstrapping dependencies for RedHat-based OSes..."
|
|
BootstrapRpmCommon
|
|
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
|
|
echo "Bootstrapping dependencies for openSUSE-based OSes..."
|
|
BootstrapSuseCommon
|
|
elif [ -f /etc/arch-release ]; then
|
|
if [ "$DEBUG" = 1 ]; then
|
|
echo "Bootstrapping dependencies for Archlinux..."
|
|
BootstrapArchCommon
|
|
else
|
|
echo "Please use pacman to install letsencrypt packages:"
|
|
echo "# pacman -S letsencrypt letsencrypt-apache"
|
|
echo
|
|
echo "If you would like to use the virtualenv way, please run the script again with the"
|
|
echo "--debug flag."
|
|
exit 1
|
|
fi
|
|
elif [ -f /etc/manjaro-release ]; then
|
|
ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon
|
|
elif [ -f /etc/gentoo-release ]; then
|
|
ExperimentalBootstrap "Gentoo" BootstrapGentooCommon
|
|
elif uname | grep -iq FreeBSD ; then
|
|
ExperimentalBootstrap "FreeBSD" BootstrapFreeBsd
|
|
elif uname | grep -iq Darwin ; then
|
|
ExperimentalBootstrap "Mac OS X" BootstrapMac
|
|
elif grep -iq "Amazon Linux" /etc/issue ; then
|
|
ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
|
|
else
|
|
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"
|
|
echo "for more info."
|
|
fi
|
|
}
|
|
|
|
TempDir() {
|
|
mktemp -d 2>/dev/null || mktemp -d -t 'le' # Linux || OS X
|
|
}
|
|
|
|
|
|
|
|
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
|
|
INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep ^letsencrypt | cut -d " " -f 2)
|
|
else
|
|
INSTALLED_VERSION="none"
|
|
fi
|
|
if [ "$LE_AUTO_VERSION" != "$INSTALLED_VERSION" ]; then
|
|
echo "Creating virtual environment..."
|
|
DeterminePythonVersion
|
|
rm -rf "$VENV_PATH"
|
|
if [ "$VERBOSE" = 1 ]; then
|
|
virtualenv --no-site-packages --python "$LE_PYTHON" "$VENV_PATH"
|
|
else
|
|
virtualenv --no-site-packages --python "$LE_PYTHON" "$VENV_PATH" > /dev/null
|
|
fi
|
|
|
|
echo "Installing Python packages..."
|
|
TEMP_DIR=$(TempDir)
|
|
# There is no $ interpolation due to quotes on starting heredoc delimiter.
|
|
# -------------------------------------------------------------------------
|
|
cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt"
|
|
{{ letsencrypt-auto-requirements.txt }}
|
|
UNLIKELY_EOF
|
|
# -------------------------------------------------------------------------
|
|
cat << "UNLIKELY_EOF" > "$TEMP_DIR/pipstrap.py"
|
|
{{ pipstrap.py }}
|
|
UNLIKELY_EOF
|
|
# -------------------------------------------------------------------------
|
|
# Set PATH so pipstrap upgrades the right (v)env:
|
|
PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py"
|
|
set +e
|
|
PIP_OUT=`"$VENV_BIN/pip" install --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1`
|
|
PIP_STATUS=$?
|
|
set -e
|
|
rm -rf "$TEMP_DIR"
|
|
if [ "$PIP_STATUS" != 0 ]; then
|
|
# Report error. (Otherwise, be quiet.)
|
|
echo "Had a problem while installing Python packages:"
|
|
echo "$PIP_OUT"
|
|
rm -rf "$VENV_PATH"
|
|
exit 1
|
|
fi
|
|
echo "Installation succeeded."
|
|
fi
|
|
echo "Requesting root privileges to run certbot..."
|
|
echo " " $SUDO "$VENV_BIN/letsencrypt" "$@"
|
|
$SUDO "$VENV_BIN/letsencrypt" "$@"
|
|
else
|
|
# Phase 1: Upgrade letsencrypt-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
|
|
# package). Phase 2 checks the version of the locally installed certbot.
|
|
|
|
if [ ! -f "$VENV_BIN/letsencrypt" ]; then
|
|
# If it looks like we've never bootstrapped before, bootstrap:
|
|
Bootstrap
|
|
fi
|
|
if [ "$OS_PACKAGES_ONLY" = 1 ]; then
|
|
echo "OS packages installed."
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$NO_SELF_UPGRADE" != 1 ]; then
|
|
echo "Checking for new version..."
|
|
TEMP_DIR=$(TempDir)
|
|
# ---------------------------------------------------------------------------
|
|
cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py"
|
|
{{ fetch.py }}
|
|
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..."
|
|
|
|
# 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.
|
|
# TODO: Deal with quotes in pathnames.
|
|
echo "Replacing letsencrypt-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"
|
|
fi # A newer version is available.
|
|
fi # Self-upgrading is allowed.
|
|
|
|
"$0" --le-auto-phase2 "$@"
|
|
fi
|