diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto
index 39f8728e8..8ce3342be 100755
--- a/letsencrypt-auto-source/letsencrypt-auto
+++ b/letsencrypt-auto-source/letsencrypt-auto
@@ -23,9 +23,11 @@ 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.18.0.dev0"
@@ -49,6 +51,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
@@ -119,16 +122,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 +152,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
@@ -261,7 +279,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 +329,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 +354,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 \
@@ -380,9 +398,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 +412,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
@@ -411,7 +429,7 @@ BootstrapRpmCommon() {
"
# Most RPM distros use the "python" or "python-" naming convention. Let's try that first.
- if $SUDO $tool list python >/dev/null 2>&1; then
+ if $tool list python >/dev/null 2>&1; then
pkgs="$pkgs
python
python-devel
@@ -421,7 +439,7 @@ BootstrapRpmCommon() {
"
# Fedora 26 starts to use the prefix python2 for python2 based packages.
# this elseif is theoretically for any Fedora over version 26:
- elif $SUDO $tool list python2 >/dev/null 2>&1; then
+ elif $tool list python2 >/dev/null 2>&1; then
pkgs="$pkgs
python2
python2-libs
@@ -443,13 +461,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
@@ -467,7 +485,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 \
@@ -498,7 +516,7 @@ 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"
@@ -506,9 +524,9 @@ BootstrapArchCommon() {
if [ "$missing" ]; then
if [ "$QUIET" = 1 ]; then
- $SUDO pacman -S --needed $missing $noconfirm > /dev/null
+ pacman -S --needed $missing $noconfirm > /dev/null
else
- $SUDO pacman -S --needed $missing $noconfirm
+ pacman -S --needed $missing $noconfirm
fi
fi
}
@@ -530,13 +548,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
}
@@ -546,7 +564,7 @@ BootstrapFreeBsd() {
QUIET_FLAG="--quiet"
fi
- $SUDO pkg install -Ay $QUIET_FLAG \
+ pkg install -Ay $QUIET_FLAG \
python \
py27-virtualenv \
augeas \
@@ -561,7 +579,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)"
@@ -581,8 +599,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
@@ -608,7 +626,7 @@ BootstrapMageiaCommon() {
QUIET_FLAG='--quiet'
fi
- if ! $SUDO urpmi --force $QUIET_FLAG \
+ if ! urpmi --force $QUIET_FLAG \
python \
libpython-devel \
python-virtualenv
@@ -617,7 +635,7 @@ BootstrapMageiaCommon() {
exit 1
fi
- if ! $SUDO urpmi --force $QUIET_FLAG \
+ if ! urpmi --force $QUIET_FLAG \
git \
gcc \
python-augeas \
@@ -1144,20 +1162,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.
@@ -1168,12 +1181,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."
@@ -1333,13 +1348,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.
diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template
index 284241a82..29aaf1291 100755
--- a/letsencrypt-auto-source/letsencrypt-auto.template
+++ b/letsencrypt-auto-source/letsencrypt-auto.template
@@ -23,9 +23,11 @@ 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="{{ LE_AUTO_VERSION }}"
@@ -49,6 +51,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
@@ -119,16 +122,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 +152,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
@@ -385,20 +403,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 +422,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 +460,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.
diff --git a/letsencrypt-auto-source/pieces/bootstrappers/arch_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/arch_common.sh
index e9d91fe70..3983bc1d8 100755
--- a/letsencrypt-auto-source/pieces/bootstrappers/arch_common.sh
+++ b/letsencrypt-auto-source/pieces/bootstrappers/arch_common.sh
@@ -18,7 +18,7 @@ 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"
@@ -26,9 +26,9 @@ BootstrapArchCommon() {
if [ "$missing" ]; then
if [ "$QUIET" = 1 ]; then
- $SUDO pacman -S --needed $missing $noconfirm > /dev/null
+ pacman -S --needed $missing $noconfirm > /dev/null
else
- $SUDO pacman -S --needed $missing $noconfirm
+ pacman -S --needed $missing $noconfirm
fi
fi
}
diff --git a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh
index afd279ac2..12aa80d63 100644
--- a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh
+++ b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh
@@ -21,7 +21,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 +71,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 +96,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 \
diff --git a/letsencrypt-auto-source/pieces/bootstrappers/free_bsd.sh b/letsencrypt-auto-source/pieces/bootstrappers/free_bsd.sh
index f1bc00f3b..cfbd2b8b1 100755
--- a/letsencrypt-auto-source/pieces/bootstrappers/free_bsd.sh
+++ b/letsencrypt-auto-source/pieces/bootstrappers/free_bsd.sh
@@ -3,7 +3,7 @@ BootstrapFreeBsd() {
QUIET_FLAG="--quiet"
fi
- $SUDO pkg install -Ay $QUIET_FLAG \
+ pkg install -Ay $QUIET_FLAG \
python \
py27-virtualenv \
augeas \
diff --git a/letsencrypt-auto-source/pieces/bootstrappers/gentoo_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/gentoo_common.sh
index 86a1ec7d6..46543bab9 100755
--- a/letsencrypt-auto-source/pieces/bootstrappers/gentoo_common.sh
+++ b/letsencrypt-auto-source/pieces/bootstrappers/gentoo_common.sh
@@ -15,13 +15,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
}
diff --git a/letsencrypt-auto-source/pieces/bootstrappers/mac.sh b/letsencrypt-auto-source/pieces/bootstrappers/mac.sh
index b88e96999..b9f347f67 100755
--- a/letsencrypt-auto-source/pieces/bootstrappers/mac.sh
+++ b/letsencrypt-auto-source/pieces/bootstrappers/mac.sh
@@ -6,7 +6,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 +26,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
diff --git a/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh
index 1c76bbcac..c9a540ce1 100644
--- a/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh
+++ b/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh
@@ -3,7 +3,7 @@ BootstrapMageiaCommon() {
QUIET_FLAG='--quiet'
fi
- if ! $SUDO urpmi --force $QUIET_FLAG \
+ if ! urpmi --force $QUIET_FLAG \
python \
libpython-devel \
python-virtualenv
@@ -12,7 +12,7 @@ BootstrapMageiaCommon() {
exit 1
fi
- if ! $SUDO urpmi --force $QUIET_FLAG \
+ if ! urpmi --force $QUIET_FLAG \
git \
gcc \
python-augeas \
diff --git a/letsencrypt-auto-source/pieces/bootstrappers/rpm_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/rpm_common.sh
index 965ee32f3..129684338 100755
--- a/letsencrypt-auto-source/pieces/bootstrappers/rpm_common.sh
+++ b/letsencrypt-auto-source/pieces/bootstrappers/rpm_common.sh
@@ -24,9 +24,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 +38,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
@@ -55,7 +55,7 @@ BootstrapRpmCommon() {
"
# Most RPM distros use the "python" or "python-" naming convention. Let's try that first.
- if $SUDO $tool list python >/dev/null 2>&1; then
+ if $tool list python >/dev/null 2>&1; then
pkgs="$pkgs
python
python-devel
@@ -65,7 +65,7 @@ BootstrapRpmCommon() {
"
# Fedora 26 starts to use the prefix python2 for python2 based packages.
# this elseif is theoretically for any Fedora over version 26:
- elif $SUDO $tool list python2 >/dev/null 2>&1; then
+ elif $tool list python2 >/dev/null 2>&1; then
pkgs="$pkgs
python2
python2-libs
@@ -87,13 +87,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
diff --git a/letsencrypt-auto-source/pieces/bootstrappers/suse_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/suse_common.sh
index e60ca8628..56e7acda3 100755
--- a/letsencrypt-auto-source/pieces/bootstrappers/suse_common.sh
+++ b/letsencrypt-auto-source/pieces/bootstrappers/suse_common.sh
@@ -10,7 +10,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 \
diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py
index 6f21c28d5..5c63325ee 100644
--- a/letsencrypt-auto-source/tests/auto_test.py
+++ b/letsencrypt-auto-source/tests/auto_test.py
@@ -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 = {'': 'certbot/',
@@ -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 = {'': 'certbot/',
'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 "