Replace platform.linux_distribution with distro.linux_distribution (#7337)
[letsencrypt.git] / letsencrypt-auto-source / letsencrypt-auto
1 #!/bin/sh
2 #
3 # Download and run the latest release version of the Certbot client.
4 #
5 # NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING
6 #
7 # IF YOU WANT TO EDIT IT LOCALLY, *ALWAYS* RUN YOUR COPY WITH THE
8 # "--no-self-upgrade" FLAG
9 #
10 # IF YOU WANT TO SEND PULL REQUESTS, THE REAL SOURCE FOR THIS FILE IS
11 # letsencrypt-auto-source/letsencrypt-auto.template AND
12 # letsencrypt-auto-source/pieces/bootstrappers/*
13
14 set -e  # Work even if somebody does "sh thisscript.sh".
15
16 # Note: you can set XDG_DATA_HOME or VENV_PATH before running this script,
17 # if you want to change where the virtual environment will be installed
18
19 # HOME might not be defined when being run through something like systemd
20 if [ -z "$HOME" ]; then
21   HOME=~root
22 fi
23 if [ -z "$XDG_DATA_HOME" ]; then
24   XDG_DATA_HOME=~/.local/share
25 fi
26 if [ -z "$VENV_PATH" ]; then
27   # We export these values so they are preserved properly if this script is
28   # rerun with sudo/su where $HOME/$XDG_DATA_HOME may have a different value.
29   export OLD_VENV_PATH="$XDG_DATA_HOME/letsencrypt"
30   export VENV_PATH="/opt/eff.org/certbot/venv"
31 fi
32 VENV_BIN="$VENV_PATH/bin"
33 BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
34 LE_AUTO_VERSION="0.38.0.dev0"
35 BASENAME=$(basename $0)
36 USAGE="Usage: $BASENAME [OPTIONS]
37 A self-updating wrapper script for the Certbot ACME client. When run, updates
38 to both this script and certbot will be downloaded and installed. After
39 ensuring you have the latest versions installed, certbot will be invoked with
40 all arguments you have provided.
41
42 Help for certbot itself cannot be provided until it is installed.
43
44   --debug                                   attempt experimental installation
45   -h, --help                                print this help
46   -n, --non-interactive, --noninteractive   run without asking for user input
47   --no-bootstrap                            do not install OS dependencies
48   --no-permissions-check                    do not warn about file system permissions
49   --no-self-upgrade                         do not download updates
50   --os-packages-only                        install OS dependencies and exit
51   --install-only                            install certbot, upgrade if needed, and exit
52   -v, --verbose                             provide more output
53   -q, --quiet                               provide only update/error output;
54                                             implies --non-interactive
55
56 All arguments are accepted and forwarded to the Certbot client when run."
57 export CERTBOT_AUTO="$0"
58
59 for arg in "$@" ; do
60   case "$arg" in
61     --debug)
62       DEBUG=1;;
63     --os-packages-only)
64       OS_PACKAGES_ONLY=1;;
65     --install-only)
66       INSTALL_ONLY=1;;
67     --no-self-upgrade)
68       # Do not upgrade this script (also prevents client upgrades, because each
69       # copy of the script pins a hash of the python client)
70       NO_SELF_UPGRADE=1;;
71     --no-permissions-check)
72       NO_PERMISSIONS_CHECK=1;;
73     --no-bootstrap)
74       NO_BOOTSTRAP=1;;
75     --help)
76       HELP=1;;
77     --noninteractive|--non-interactive)
78       NONINTERACTIVE=1;;
79     --quiet)
80       QUIET=1;;
81     renew)
82       ASSUME_YES=1;;
83     --verbose)
84       VERBOSE=1;;
85     -[!-]*)
86       OPTIND=1
87       while getopts ":hnvq" short_arg $arg; do
88         case "$short_arg" in
89           h)
90             HELP=1;;
91           n)
92             NONINTERACTIVE=1;;
93           q)
94             QUIET=1;;
95           v)
96             VERBOSE=1;;
97         esac
98       done;;
99   esac
100 done
101
102 if [ $BASENAME = "letsencrypt-auto" ]; then
103   # letsencrypt-auto does not respect --help or --yes for backwards compatibility
104   NONINTERACTIVE=1
105   HELP=0
106 fi
107
108 # Set ASSUME_YES to 1 if QUIET or NONINTERACTIVE
109 if [ "$QUIET" = 1 -o "$NONINTERACTIVE" = 1 ]; then
110   ASSUME_YES=1
111 fi
112
113 say() {
114     if [  "$QUIET" != 1 ]; then
115         echo "$@"
116     fi
117 }
118
119 error() {
120     echo "$@"
121 }
122
123 # Support for busybox and others where there is no "command",
124 # but "which" instead
125 if command -v command > /dev/null 2>&1 ; then
126   export EXISTS="command -v"
127 elif which which > /dev/null 2>&1 ; then
128   export EXISTS="which"
129 else
130   error "Cannot find command nor which... please install one!"
131   exit 1
132 fi
133
134 # Certbot itself needs root access for almost all modes of operation.
135 # certbot-auto needs root access to bootstrap OS dependencies and install
136 # Certbot at a protected path so it can be safely run as root. To accomplish
137 # this, this script will attempt to run itself as root if it doesn't have the
138 # necessary privileges by using `sudo` or falling back to `su` if it is not
139 # available. The mechanism used to obtain root access can be set explicitly by
140 # setting the environment variable LE_AUTO_SUDO to 'sudo', 'su', 'su_sudo',
141 # 'SuSudo', or '' as used below.
142
143 # Because the parameters in `su -c` has to be a string,
144 # we need to properly escape it.
145 SuSudo() {
146   args=""
147   # This `while` loop iterates over all parameters given to this function.
148   # For each parameter, all `'` will be replace by `'"'"'`, and the escaped string
149   # will be wrapped in a pair of `'`, then appended to `$args` string
150   # For example, `echo "It's only 1\$\!"` will be escaped to:
151   #   'echo' 'It'"'"'s only 1$!'
152   #     │       │└┼┘│
153   #     │       │ │ └── `'s only 1$!'` the literal string
154   #     │       │ └── `\"'\"` is a single quote (as a string)
155   #     │       └── `'It'`, to be concatenated with the strings following it
156   #     └── `echo` wrapped in a pair of `'`, it's totally fine for the shell command itself
157   while [ $# -ne 0 ]; do
158     args="$args'$(printf "%s" "$1" | sed -e "s/'/'\"'\"'/g")' "
159     shift
160   done
161   su root -c "$args"
162 }
163
164 # Sets the environment variable SUDO to be the name of the program or function
165 # to call to get root access. If this script already has root privleges, SUDO
166 # is set to an empty string. The value in SUDO should be run with the command
167 # to called with root privileges as arguments.
168 SetRootAuthMechanism() {
169   SUDO=""
170   if [ -n "${LE_AUTO_SUDO+x}" ]; then
171     case "$LE_AUTO_SUDO" in
172       SuSudo|su_sudo|su)
173         SUDO=SuSudo
174         ;;
175       sudo)
176         SUDO="sudo -E"
177         ;;
178       '')
179         # If we're not running with root, don't check that this script can only
180         # be modified by system users and groups.
181         NO_PERMISSIONS_CHECK=1
182         ;;
183       *)
184         error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
185         exit 1
186     esac
187     say "Using preset root authorization mechanism '$LE_AUTO_SUDO'."
188   else
189     if test "`id -u`" -ne "0" ; then
190       if $EXISTS sudo 1>/dev/null 2>&1; then
191         SUDO="sudo -E"
192       else
193         say \"sudo\" is not available, will use \"su\" for installation steps...
194         SUDO=SuSudo
195       fi
196     fi
197   fi
198 }
199
200 if [ "$1" = "--cb-auto-has-root" ]; then
201   shift 1
202 else
203   SetRootAuthMechanism
204   if [ -n "$SUDO" ]; then
205     say "Requesting to rerun $0 with root privileges..."
206     $SUDO "$0" --cb-auto-has-root "$@"
207     exit 0
208   fi
209 fi
210
211 # Runs this script again with the given arguments. --cb-auto-has-root is added
212 # to the command line arguments to ensure we don't try to acquire root a
213 # second time. After the script is rerun, we exit the current script.
214 RerunWithArgs() {
215     "$0" --cb-auto-has-root "$@"
216     exit 0
217 }
218
219 BootstrapMessage() {
220   # Arguments: Platform name
221   say "Bootstrapping dependencies for $1... (you can skip this with --no-bootstrap)"
222 }
223
224 ExperimentalBootstrap() {
225   # Arguments: Platform name, bootstrap function name
226   if [ "$DEBUG" = 1 ]; then
227     if [ "$2" != "" ]; then
228       BootstrapMessage $1
229       $2
230     fi
231   else
232     error "FATAL: $1 support is very experimental at present..."
233     error "if you would like to work on improving it, please ensure you have backups"
234     error "and then run this script again with the --debug flag!"
235     error "Alternatively, you can install OS dependencies yourself and run this script"
236     error "again with --no-bootstrap."
237     exit 1
238   fi
239 }
240
241 DeprecationBootstrap() {
242   # Arguments: Platform name, bootstrap function name
243   if [ "$DEBUG" = 1 ]; then
244     if [ "$2" != "" ]; then
245       BootstrapMessage $1
246       $2
247     fi
248   else
249     error "WARNING: certbot-auto support for this $1 is DEPRECATED!"
250     error "Please visit certbot.eff.org to learn how to download a version of"
251     error "Certbot that is packaged for your system. While an existing version"
252     error "of certbot-auto may work currently, we have stopped supporting updating"
253     error "system packages for your system. Please switch to a packaged version"
254     error "as soon as possible."
255     exit 1
256   fi
257 }
258
259 MIN_PYTHON_VERSION="2.7"
260 MIN_PYVER=$(echo "$MIN_PYTHON_VERSION" | sed 's/\.//')
261 # Sets LE_PYTHON to Python version string and PYVER to the first two
262 # digits of the python version
263 DeterminePythonVersion() {
264   # Arguments: "NOCRASH" if we shouldn't crash if we don't find a good python
265   #
266   # If no Python is found, PYVER is set to 0.
267   if [ "$USE_PYTHON_3" = 1 ]; then
268     for LE_PYTHON in "$LE_PYTHON" python3; do
269       # Break (while keeping the LE_PYTHON value) if found.
270       $EXISTS "$LE_PYTHON" > /dev/null && break
271     done
272   else
273     for LE_PYTHON in "$LE_PYTHON" python2.7 python27 python2 python; do
274       # Break (while keeping the LE_PYTHON value) if found.
275       $EXISTS "$LE_PYTHON" > /dev/null && break
276     done
277   fi
278   if [ "$?" != "0" ]; then
279     if [ "$1" != "NOCRASH" ]; then
280       error "Cannot find any Pythons; please install one!"
281       exit 1
282     else
283       PYVER=0
284       return 0
285     fi
286   fi
287
288   PYVER=`"$LE_PYTHON" -V 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed 's/\.//'`
289   if [ "$PYVER" -lt "$MIN_PYVER" ]; then
290     if [ "$1" != "NOCRASH" ]; then
291       error "You have an ancient version of Python entombed in your operating system..."
292       error "This isn't going to work; you'll need at least version $MIN_PYTHON_VERSION."
293       exit 1
294     fi
295   fi
296 }
297
298 # If new packages are installed by BootstrapDebCommon below, this version
299 # number must be increased.
300 BOOTSTRAP_DEB_COMMON_VERSION=1
301
302 BootstrapDebCommon() {
303   # Current version tested with:
304   #
305   # - Ubuntu
306   #     - 14.04 (x64)
307   #     - 15.04 (x64)
308   # - Debian
309   #     - 7.9 "wheezy" (x64)
310   #     - sid (2015-10-21) (x64)
311
312   # Past versions tested with:
313   #
314   # - Debian 8.0 "jessie" (x64)
315   # - Raspbian 7.8 (armhf)
316
317   # Believed not to work:
318   #
319   # - Debian 6.0.10 "squeeze" (x64)
320
321   if [ "$QUIET" = 1 ]; then
322     QUIET_FLAG='-qq'
323   fi
324
325   apt-get $QUIET_FLAG update || error apt-get update hit problems but continuing anyway...
326
327   # virtualenv binary can be found in different packages depending on
328   # distro version (#346)
329
330   virtualenv=
331   # virtual env is known to apt and is installable
332   if apt-cache show virtualenv > /dev/null 2>&1 ; then
333     if ! LC_ALL=C apt-cache --quiet=0 show virtualenv 2>&1 | grep -q 'No packages found'; then
334       virtualenv="virtualenv"
335     fi
336   fi
337
338   if apt-cache show python-virtualenv > /dev/null 2>&1; then
339     virtualenv="$virtualenv python-virtualenv"
340   fi
341
342   augeas_pkg="libaugeas0 augeas-lenses"
343
344   if [ "$ASSUME_YES" = 1 ]; then
345     YES_FLAG="-y"
346   fi
347
348   apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends \
349     python \
350     python-dev \
351     $virtualenv \
352     gcc \
353     $augeas_pkg \
354     libssl-dev \
355     openssl \
356     libffi-dev \
357     ca-certificates \
358
359
360   if ! $EXISTS virtualenv > /dev/null ; then
361     error Failed to install a working \"virtualenv\" command, exiting
362     exit 1
363   fi
364 }
365
366 # If new packages are installed by BootstrapRpmCommonBase below, version
367 # numbers in rpm_common.sh and rpm_python3.sh must be increased.
368
369 # Sets TOOL to the name of the package manager
370 # Sets appropriate values for YES_FLAG and QUIET_FLAG based on $ASSUME_YES and $QUIET_FLAG.
371 # Enables EPEL if applicable and possible.
372 InitializeRPMCommonBase() {
373   if type dnf 2>/dev/null
374   then
375     TOOL=dnf
376   elif type yum 2>/dev/null
377   then
378     TOOL=yum
379
380   else
381     error "Neither yum nor dnf found. Aborting bootstrap!"
382     exit 1
383   fi
384
385   if [ "$ASSUME_YES" = 1 ]; then
386     YES_FLAG="-y"
387   fi
388   if [ "$QUIET" = 1 ]; then
389     QUIET_FLAG='--quiet'
390   fi
391
392   if ! $TOOL list *virtualenv >/dev/null 2>&1; then
393     echo "To use Certbot, packages from the EPEL repository need to be installed."
394     if ! $TOOL list epel-release >/dev/null 2>&1; then
395       error "Enable the EPEL repository and try running Certbot again."
396       exit 1
397     fi
398     if [ "$ASSUME_YES" = 1 ]; then
399       /bin/echo -n "Enabling the EPEL repository in 3 seconds..."
400       sleep 1s
401       /bin/echo -ne "\e[0K\rEnabling the EPEL repository in 2 seconds..."
402       sleep 1s
403       /bin/echo -e "\e[0K\rEnabling the EPEL repository in 1 second..."
404       sleep 1s
405     fi
406     if ! $TOOL install $YES_FLAG $QUIET_FLAG epel-release; then
407       error "Could not enable EPEL. Aborting bootstrap!"
408       exit 1
409     fi
410   fi
411 }
412
413 BootstrapRpmCommonBase() {
414   # Arguments: whitespace-delimited python packages to install
415
416   InitializeRPMCommonBase # This call is superfluous in practice
417
418   pkgs="
419     gcc
420     augeas-libs
421     openssl
422     openssl-devel
423     libffi-devel
424     redhat-rpm-config
425     ca-certificates
426   "
427
428   # Add the python packages
429   pkgs="$pkgs
430     $1
431   "
432
433   if $TOOL list installed "httpd" >/dev/null 2>&1; then
434     pkgs="$pkgs
435       mod_ssl
436     "
437   fi
438
439   if ! $TOOL install $YES_FLAG $QUIET_FLAG $pkgs; then
440     error "Could not install OS dependencies. Aborting bootstrap!"
441     exit 1
442   fi
443 }
444
445 # If new packages are installed by BootstrapRpmCommon below, this version
446 # number must be increased.
447 BOOTSTRAP_RPM_COMMON_VERSION=1
448
449 BootstrapRpmCommon() {
450   # Tested with:
451   #   - Fedora 20, 21, 22, 23 (x64)
452   #   - Centos 7 (x64: on DigitalOcean droplet)
453   #   - CentOS 7 Minimal install in a Hyper-V VM
454   #   - CentOS 6
455
456   InitializeRPMCommonBase
457
458   # Most RPM distros use the "python" or "python-" naming convention.  Let's try that first.
459   if $TOOL list python >/dev/null 2>&1; then
460     python_pkgs="$python
461       python-devel
462       python-virtualenv
463       python-tools
464       python-pip
465     "
466   # Fedora 26 starts to use the prefix python2 for python2 based packages.
467   # this elseif is theoretically for any Fedora over version 26:
468   elif $TOOL list python2 >/dev/null 2>&1; then
469     python_pkgs="$python2
470       python2-libs
471       python2-setuptools
472       python2-devel
473       python2-virtualenv
474       python2-tools
475       python2-pip
476     "
477   # Some distros and older versions of current distros use a "python27"
478   # instead of the "python" or "python-" naming convention.
479   else
480     python_pkgs="$python27
481       python27-devel
482       python27-virtualenv
483       python27-tools
484       python27-pip
485     "
486   fi
487
488   BootstrapRpmCommonBase "$python_pkgs"
489 }
490
491 # If new packages are installed by BootstrapRpmPython3 below, this version
492 # number must be increased.
493 BOOTSTRAP_RPM_PYTHON3_VERSION=1
494
495 BootstrapRpmPython3() {
496   # Tested with:
497   #   - CentOS 6
498   #   - Fedora 29
499
500   InitializeRPMCommonBase
501
502   # Fedora 29 must use python3-virtualenv
503   if $TOOL list python3-virtualenv >/dev/null 2>&1; then
504     python_pkgs="python3
505       python3-virtualenv
506       python3-devel
507     "
508   # EPEL uses python34
509   elif $TOOL list python34 >/dev/null 2>&1; then
510     python_pkgs="python34
511       python34-devel
512       python34-tools
513     "
514   else
515     error "No supported Python package available to install. Aborting bootstrap!"
516     exit 1
517   fi
518
519   BootstrapRpmCommonBase "$python_pkgs"
520 }
521
522 # If new packages are installed by BootstrapSuseCommon below, this version
523 # number must be increased.
524 BOOTSTRAP_SUSE_COMMON_VERSION=1
525
526 BootstrapSuseCommon() {
527   # SLE12 don't have python-virtualenv
528
529   if [ "$ASSUME_YES" = 1 ]; then
530     zypper_flags="-nq"
531     install_flags="-l"
532   fi
533
534   if [ "$QUIET" = 1 ]; then
535     QUIET_FLAG='-qq'
536   fi
537
538   if zypper search -x python-virtualenv >/dev/null 2>&1; then
539     OPENSUSE_VIRTUALENV_PACKAGES="python-virtualenv"
540   else
541     # Since Leap 15.0 (and associated Tumbleweed version), python-virtualenv
542     # is a source package, and python2-virtualenv must be used instead.
543     # Also currently python2-setuptools is not a dependency of python2-virtualenv,
544     # while it should be. Installing it explicitly until upstream fix.
545     OPENSUSE_VIRTUALENV_PACKAGES="python2-virtualenv python2-setuptools"
546   fi
547
548   zypper $QUIET_FLAG $zypper_flags in $install_flags \
549     python \
550     python-devel \
551     $OPENSUSE_VIRTUALENV_PACKAGES \
552     gcc \
553     augeas-lenses \
554     libopenssl-devel \
555     libffi-devel \
556     ca-certificates
557 }
558
559 # If new packages are installed by BootstrapArchCommon below, this version
560 # number must be increased.
561 BOOTSTRAP_ARCH_COMMON_VERSION=1
562
563 BootstrapArchCommon() {
564   # Tested with:
565   #   - ArchLinux (x86_64)
566   #
567   # "python-virtualenv" is Python3, but "python2-virtualenv" provides
568   # only "virtualenv2" binary, not "virtualenv".
569
570   deps="
571     python2
572     python-virtualenv
573     gcc
574     augeas
575     openssl
576     libffi
577     ca-certificates
578     pkg-config
579   "
580
581   # pacman -T exits with 127 if there are missing dependencies
582   missing=$(pacman -T $deps) || true
583
584   if [ "$ASSUME_YES" = 1 ]; then
585     noconfirm="--noconfirm"
586   fi
587
588   if [ "$missing" ]; then
589     if [ "$QUIET" = 1 ]; then
590       pacman -S --needed $missing $noconfirm > /dev/null
591     else
592       pacman -S --needed $missing $noconfirm
593     fi
594   fi
595 }
596
597 # If new packages are installed by BootstrapGentooCommon below, this version
598 # number must be increased.
599 BOOTSTRAP_GENTOO_COMMON_VERSION=1
600
601 BootstrapGentooCommon() {
602   PACKAGES="
603     dev-lang/python:2.7
604     dev-python/virtualenv
605     app-admin/augeas
606     dev-libs/openssl
607     dev-libs/libffi
608     app-misc/ca-certificates
609     virtual/pkgconfig"
610
611   ASK_OPTION="--ask"
612   if [ "$ASSUME_YES" = 1 ]; then
613     ASK_OPTION=""
614   fi
615
616   case "$PACKAGE_MANAGER" in
617     (paludis)
618       cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
619       ;;
620     (pkgcore)
621       pmerge --noreplace --oneshot $ASK_OPTION $PACKAGES
622       ;;
623     (portage|*)
624       emerge --noreplace --oneshot $ASK_OPTION $PACKAGES
625       ;;
626   esac
627 }
628
629 # If new packages are installed by BootstrapFreeBsd below, this version number
630 # must be increased.
631 BOOTSTRAP_FREEBSD_VERSION=1
632
633 BootstrapFreeBsd() {
634   if [ "$QUIET" = 1 ]; then
635     QUIET_FLAG="--quiet"
636   fi
637
638   pkg install -Ay $QUIET_FLAG \
639     python \
640     py27-virtualenv \
641     augeas \
642     libffi
643 }
644
645 # If new packages are installed by BootstrapMac below, this version number must
646 # be increased.
647 BOOTSTRAP_MAC_VERSION=1
648
649 BootstrapMac() {
650   if hash brew 2>/dev/null; then
651     say "Using Homebrew to install dependencies..."
652     pkgman=brew
653     pkgcmd="brew install"
654   elif hash port 2>/dev/null; then
655     say "Using MacPorts to install dependencies..."
656     pkgman=port
657     pkgcmd="port install"
658   else
659     say "No Homebrew/MacPorts; installing Homebrew..."
660     ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
661     pkgman=brew
662     pkgcmd="brew install"
663   fi
664
665   $pkgcmd augeas
666   if [ "$(which python)" = "/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python" \
667       -o "$(which python)" = "/usr/bin/python" ]; then
668     # We want to avoid using the system Python because it requires root to use pip.
669     # python.org, MacPorts or HomeBrew Python installations should all be OK.
670     say "Installing python..."
671     $pkgcmd python
672   fi
673
674   # Workaround for _dlopen not finding augeas on macOS
675   if [ "$pkgman" = "port" ] && ! [ -e "/usr/local/lib/libaugeas.dylib" ] && [ -e "/opt/local/lib/libaugeas.dylib" ]; then
676     say "Applying augeas workaround"
677     mkdir -p /usr/local/lib/
678     ln -s /opt/local/lib/libaugeas.dylib /usr/local/lib/
679   fi
680
681   if ! hash pip 2>/dev/null; then
682     say "pip not installed"
683     say "Installing pip..."
684     curl --silent --show-error --retry 5 https://bootstrap.pypa.io/get-pip.py | python
685   fi
686
687   if ! hash virtualenv 2>/dev/null; then
688     say "virtualenv not installed."
689     say "Installing with pip..."
690     pip install virtualenv
691   fi
692 }
693
694 # If new packages are installed by BootstrapSmartOS below, this version number
695 # must be increased.
696 BOOTSTRAP_SMARTOS_VERSION=1
697
698 BootstrapSmartOS() {
699   pkgin update
700   pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv'
701 }
702
703 # If new packages are installed by BootstrapMageiaCommon below, this version
704 # number must be increased.
705 BOOTSTRAP_MAGEIA_COMMON_VERSION=1
706
707 BootstrapMageiaCommon() {
708   if [ "$QUIET" = 1 ]; then
709     QUIET_FLAG='--quiet'
710   fi
711
712   if ! urpmi --force $QUIET_FLAG \
713       python \
714       libpython-devel \
715       python-virtualenv
716     then
717       error "Could not install Python dependencies. Aborting bootstrap!"
718       exit 1
719   fi
720
721   if ! urpmi --force $QUIET_FLAG \
722       git \
723       gcc \
724       python-augeas \
725       libopenssl-devel \
726       libffi-devel \
727       rootcerts
728     then
729       error "Could not install additional dependencies. Aborting bootstrap!"
730       exit 1
731     fi
732 }
733
734
735 # Set Bootstrap to the function that installs OS dependencies on this system
736 # and BOOTSTRAP_VERSION to the unique identifier for the current version of
737 # that function. If Bootstrap is set to a function that doesn't install any
738 # packages BOOTSTRAP_VERSION is not set.
739 if [ -f /etc/debian_version ]; then
740   Bootstrap() {
741     BootstrapMessage "Debian-based OSes"
742     BootstrapDebCommon
743   }
744   BOOTSTRAP_VERSION="BootstrapDebCommon $BOOTSTRAP_DEB_COMMON_VERSION"
745 elif [ -f /etc/mageia-release ]; then
746   # Mageia has both /etc/mageia-release and /etc/redhat-release
747   Bootstrap() {
748     ExperimentalBootstrap "Mageia" BootstrapMageiaCommon
749   }
750   BOOTSTRAP_VERSION="BootstrapMageiaCommon $BOOTSTRAP_MAGEIA_COMMON_VERSION"
751 elif [ -f /etc/redhat-release ]; then
752   # Run DeterminePythonVersion to decide on the basis of available Python versions
753   # whether to use 2.x or 3.x on RedHat-like systems.
754   # Then, revert LE_PYTHON to its previous state.
755   prev_le_python="$LE_PYTHON"
756   unset LE_PYTHON
757   DeterminePythonVersion "NOCRASH"
758
759   RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"`
760
761   # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on
762   # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an
763   # error, RPM_DIST_VERSION is set to "unknown".
764   RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown")
765
766   # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric
767   # characters, the value is unexpected so we set RPM_DIST_VERSION to 0.
768   if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then
769      RPM_DIST_VERSION=0
770   fi
771
772   # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
773   # RHEL 8 also uses python3 by default.
774   if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 -o "$PYVER" -eq 26 ]; then
775     RPM_USE_PYTHON_3=1
776   elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
777     RPM_USE_PYTHON_3=1
778   else
779     RPM_USE_PYTHON_3=0
780   fi
781
782   if [ "$RPM_USE_PYTHON_3" = 1 ]; then
783     Bootstrap() {
784       BootstrapMessage "RedHat-based OSes that will use Python3"
785       BootstrapRpmPython3
786     }
787     USE_PYTHON_3=1
788     BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION"
789   else
790     Bootstrap() {
791       BootstrapMessage "RedHat-based OSes"
792       BootstrapRpmCommon
793     }
794     BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
795   fi
796
797   LE_PYTHON="$prev_le_python"
798 elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
799   Bootstrap() {
800     BootstrapMessage "openSUSE-based OSes"
801     BootstrapSuseCommon
802   }
803   BOOTSTRAP_VERSION="BootstrapSuseCommon $BOOTSTRAP_SUSE_COMMON_VERSION"
804 elif [ -f /etc/arch-release ]; then
805   Bootstrap() {
806     if [ "$DEBUG" = 1 ]; then
807       BootstrapMessage "Archlinux"
808       BootstrapArchCommon
809     else
810       error "Please use pacman to install letsencrypt packages:"
811       error "# pacman -S certbot certbot-apache"
812       error
813       error "If you would like to use the virtualenv way, please run the script again with the"
814       error "--debug flag."
815       exit 1
816     fi
817   }
818   BOOTSTRAP_VERSION="BootstrapArchCommon $BOOTSTRAP_ARCH_COMMON_VERSION"
819 elif [ -f /etc/manjaro-release ]; then
820   Bootstrap() {
821     ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon
822   }
823   BOOTSTRAP_VERSION="BootstrapArchCommon $BOOTSTRAP_ARCH_COMMON_VERSION"
824 elif [ -f /etc/gentoo-release ]; then
825   Bootstrap() {
826     DeprecationBootstrap "Gentoo" BootstrapGentooCommon
827   }
828   BOOTSTRAP_VERSION="BootstrapGentooCommon $BOOTSTRAP_GENTOO_COMMON_VERSION"
829 elif uname | grep -iq FreeBSD ; then
830   Bootstrap() {
831     DeprecationBootstrap "FreeBSD" BootstrapFreeBsd
832   }
833   BOOTSTRAP_VERSION="BootstrapFreeBsd $BOOTSTRAP_FREEBSD_VERSION"
834 elif uname | grep -iq Darwin ; then
835   Bootstrap() {
836     DeprecationBootstrap "macOS" BootstrapMac
837   }
838   BOOTSTRAP_VERSION="BootstrapMac $BOOTSTRAP_MAC_VERSION"
839 elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
840   Bootstrap() {
841     ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
842   }
843   BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
844 elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then
845   Bootstrap() {
846     ExperimentalBootstrap "Joyent SmartOS Zone" BootstrapSmartOS
847   }
848   BOOTSTRAP_VERSION="BootstrapSmartOS $BOOTSTRAP_SMARTOS_VERSION"
849 else
850   Bootstrap() {
851     error "Sorry, I don't know how to bootstrap Certbot on your operating system!"
852     error
853     error "You will need to install OS dependencies, configure virtualenv, and run pip install manually."
854     error "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites"
855     error "for more info."
856     exit 1
857   }
858 fi
859
860 # We handle this case after determining the normal bootstrap version to allow
861 # variables like USE_PYTHON_3 to be properly set. As described above, if the
862 # Bootstrap function doesn't install any packages, BOOTSTRAP_VERSION should not
863 # be set so we unset it here.
864 if [ "$NO_BOOTSTRAP" = 1 ]; then
865   Bootstrap() {
866     :
867   }
868   unset BOOTSTRAP_VERSION
869 fi
870
871 # Sets PREV_BOOTSTRAP_VERSION to the identifier for the bootstrap script used
872 # to install OS dependencies on this system. PREV_BOOTSTRAP_VERSION isn't set
873 # if it is unknown how OS dependencies were installed on this system.
874 SetPrevBootstrapVersion() {
875   if [ -f $BOOTSTRAP_VERSION_PATH ]; then
876     PREV_BOOTSTRAP_VERSION=$(cat "$BOOTSTRAP_VERSION_PATH")
877   # The list below only contains bootstrap version strings that existed before
878   # we started writing them to disk.
879   #
880   # DO NOT MODIFY THIS LIST UNLESS YOU KNOW WHAT YOU'RE DOING!
881   elif grep -Fqx "$BOOTSTRAP_VERSION" << "UNLIKELY_EOF"
882 BootstrapDebCommon 1
883 BootstrapMageiaCommon 1
884 BootstrapRpmCommon 1
885 BootstrapSuseCommon 1
886 BootstrapArchCommon 1
887 BootstrapGentooCommon 1
888 BootstrapFreeBsd 1
889 BootstrapMac 1
890 BootstrapSmartOS 1
891 UNLIKELY_EOF
892   then
893     # If there's no bootstrap version saved to disk, but the currently selected
894     # bootstrap script is from before we started saving the version number,
895     # return the currently selected version to prevent us from rebootstrapping
896     # unnecessarily.
897     PREV_BOOTSTRAP_VERSION="$BOOTSTRAP_VERSION"
898   fi
899 }
900
901 TempDir() {
902   mktemp -d 2>/dev/null || mktemp -d -t 'le'  # Linux || macOS
903 }
904
905 # Returns 0 if a letsencrypt installation exists at $OLD_VENV_PATH, otherwise,
906 # returns a non-zero number.
907 OldVenvExists() {
908     [ -n "$OLD_VENV_PATH" -a -f "$OLD_VENV_PATH/bin/letsencrypt" ]
909 }
910
911 # Given python path, version 1 and version 2, check if version 1 is outdated compared to version 2.
912 # An unofficial version provided as version 1 (eg. 0.28.0.dev0) will be treated
913 # specifically by printing "UNOFFICIAL". Otherwise, print "OUTDATED" if version 1
914 # is outdated, and "UP_TO_DATE" if not.
915 # This function relies only on installed python environment (2.x or 3.x) by certbot-auto.
916 CompareVersions() {
917     "$1" - "$2" "$3" << "UNLIKELY_EOF"
918 import sys
919 from distutils.version import StrictVersion
920
921 try:
922     current = StrictVersion(sys.argv[1])
923 except ValueError:
924     sys.stdout.write('UNOFFICIAL')
925     sys.exit()
926
927 try:
928     remote = StrictVersion(sys.argv[2])
929 except ValueError:
930     sys.stdout.write('UP_TO_DATE')
931     sys.exit()
932
933 if current < remote:
934     sys.stdout.write('OUTDATED')
935 else:
936     sys.stdout.write('UP_TO_DATE')
937 UNLIKELY_EOF
938 }
939
940 # Create a new virtual environment for Certbot. It will overwrite any existing one.
941 # Parameters: LE_PYTHON, VENV_PATH, PYVER, VERBOSE
942 CreateVenv() {
943     "$1" - "$2" "$3" "$4" << "UNLIKELY_EOF"
944 #!/usr/bin/env python
945 import os
946 import shutil
947 import subprocess
948 import sys
949
950
951 def create_venv(venv_path, pyver, verbose):
952     if os.path.exists(venv_path):
953         shutil.rmtree(venv_path)
954
955     stdout = sys.stdout if verbose == '1' else open(os.devnull, 'w')
956
957     if int(pyver) <= 27:
958         # Use virtualenv binary
959         environ = os.environ.copy()
960         environ['VIRTUALENV_NO_DOWNLOAD'] = '1'
961         command = ['virtualenv', '--no-site-packages', '--python', sys.executable, venv_path]
962         subprocess.check_call(command, stdout=stdout, env=environ)
963     else:
964         # Use embedded venv module in Python 3
965         command = [sys.executable, '-m', 'venv', venv_path]
966         subprocess.check_call(command, stdout=stdout)
967
968
969 if __name__ == '__main__':
970     create_venv(*sys.argv[1:])
971
972 UNLIKELY_EOF
973 }
974
975 # Check that the given PATH_TO_CHECK has secured permissions.
976 # Parameters: LE_PYTHON, PATH_TO_CHECK
977 CheckPathPermissions() {
978     "$1" - "$2" << "UNLIKELY_EOF"
979 """Verifies certbot-auto cannot be modified by unprivileged users.
980
981 This script takes the path to certbot-auto as its only command line
982 argument.  It then checks that the file can only be modified by uid/gid
983 < 1000 and if other users can modify the file, it prints a warning with
984 a suggestion on how to solve the problem.
985
986 Permissions on symlinks in the absolute path of certbot-auto are ignored
987 and only the canonical path to certbot-auto is checked. There could be
988 permissions problems due to the symlinks that are unreported by this
989 script, however, issues like this were not caused by our documentation
990 and are ignored for the sake of simplicity.
991
992 All warnings are printed to stdout rather than stderr so all stderr
993 output from this script can be suppressed to avoid printing messages if
994 this script fails for some reason.
995
996 """
997 from __future__ import print_function
998
999 import os
1000 import stat
1001 import sys
1002
1003
1004 FORUM_POST_URL = 'https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/'
1005
1006
1007 def has_safe_permissions(path):
1008     """Returns True if the given path has secure permissions.
1009
1010     The permissions are considered safe if the file is only writable by
1011     uid/gid < 1000.
1012
1013     The reason we allow more IDs than 0 is because on some systems such
1014     as Debian, system users/groups other than uid/gid 0 are used for the
1015     path we recommend in our instructions which is /usr/local/bin.  1000
1016     was chosen because on Debian 0-999 is reserved for system IDs[1] and
1017     on RHEL either 0-499 or 0-999 is reserved depending on the
1018     version[2][3]. Due to these differences across different OSes, this
1019     detection isn't perfect so we only determine permissions are
1020     insecure when we can be reasonably confident there is a problem
1021     regardless of the underlying OS.
1022
1023     [1] https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes
1024     [2] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/ch-managing_users_and_groups
1025     [3] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-managing_users_and_groups
1026
1027     :param str path: filesystem path to check
1028     :returns: True if the path has secure permissions, otherwise, False
1029     :rtype: bool
1030
1031     """
1032     # os.stat follows symlinks before obtaining information about a file.
1033     stat_result = os.stat(path)
1034     if stat_result.st_mode & stat.S_IWOTH:
1035         return False
1036     if stat_result.st_mode & stat.S_IWGRP and stat_result.st_gid >= 1000:
1037         return False
1038     if stat_result.st_mode & stat.S_IWUSR and stat_result.st_uid >= 1000:
1039         return False
1040     return True
1041
1042
1043 def main(certbot_auto_path):
1044     current_path = os.path.realpath(certbot_auto_path)
1045     last_path = None
1046     permissions_ok = True
1047     # This loop makes use of the fact that os.path.dirname('/') == '/'.
1048     while current_path != last_path and permissions_ok:
1049         permissions_ok = has_safe_permissions(current_path)
1050         last_path = current_path
1051         current_path = os.path.dirname(current_path)
1052
1053     if not permissions_ok:
1054         print('{0} has insecure permissions!'.format(certbot_auto_path))
1055         print('To learn how to fix them, visit {0}'.format(FORUM_POST_URL))
1056
1057
1058 if __name__ == '__main__':
1059     main(sys.argv[1])
1060
1061 UNLIKELY_EOF
1062 }
1063
1064 if [ "$1" = "--le-auto-phase2" ]; then
1065   # Phase 2: Create venv, install LE, and run.
1066
1067   shift 1  # the --le-auto-phase2 arg
1068   SetPrevBootstrapVersion
1069
1070   if [ -z "$PHASE_1_VERSION" -a "$USE_PYTHON_3" = 1 ]; then
1071     unset LE_PYTHON
1072   fi
1073
1074   INSTALLED_VERSION="none"
1075   if [ -d "$VENV_PATH" ] || OldVenvExists; then
1076     # If the selected Bootstrap function isn't a noop and it differs from the
1077     # previously used version
1078     if [ -n "$BOOTSTRAP_VERSION" -a "$BOOTSTRAP_VERSION" != "$PREV_BOOTSTRAP_VERSION" ]; then
1079       # if non-interactive mode or stdin and stdout are connected to a terminal
1080       if [ \( "$NONINTERACTIVE" = 1 \) -o \( \( -t 0 \) -a \( -t 1 \) \) ]; then
1081         if [ -d "$VENV_PATH" ]; then
1082           rm -rf "$VENV_PATH"
1083         fi
1084         # In the case the old venv was just a symlink to the new one,
1085         # OldVenvExists is now false because we deleted the venv at VENV_PATH.
1086         if OldVenvExists; then
1087           rm -rf "$OLD_VENV_PATH"
1088           ln -s "$VENV_PATH" "$OLD_VENV_PATH"
1089         fi
1090         RerunWithArgs "$@"
1091       else
1092         error "Skipping upgrade because new OS dependencies may need to be installed."
1093         error
1094         error "To upgrade to a newer version, please run this script again manually so you can"
1095         error "approve changes or with --non-interactive on the command line to automatically"
1096         error "install any required packages."
1097         # Set INSTALLED_VERSION to be the same so we don't update the venv
1098         INSTALLED_VERSION="$LE_AUTO_VERSION"
1099         # Continue to use OLD_VENV_PATH if the new venv doesn't exist
1100         if [ ! -d "$VENV_PATH" ]; then
1101           VENV_BIN="$OLD_VENV_PATH/bin"
1102         fi
1103       fi
1104     elif [ -f "$VENV_BIN/letsencrypt" ]; then
1105       # --version output ran through grep due to python-cryptography DeprecationWarnings
1106       # grep for both certbot and letsencrypt until certbot and shim packages have been released
1107       INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2)
1108       if [ -z "$INSTALLED_VERSION" ]; then
1109           error "Error: couldn't get currently installed version for $VENV_BIN/letsencrypt: " 1>&2
1110           "$VENV_BIN/letsencrypt" --version
1111           exit 1
1112       fi
1113     fi
1114   fi
1115
1116   if [ "$LE_AUTO_VERSION" != "$INSTALLED_VERSION" ]; then
1117     say "Creating virtual environment..."
1118     DeterminePythonVersion
1119     CreateVenv "$LE_PYTHON" "$VENV_PATH" "$PYVER" "$VERBOSE"
1120
1121     if [ -n "$BOOTSTRAP_VERSION" ]; then
1122       echo "$BOOTSTRAP_VERSION" > "$BOOTSTRAP_VERSION_PATH"
1123     elif [ -n "$PREV_BOOTSTRAP_VERSION" ]; then
1124       echo "$PREV_BOOTSTRAP_VERSION" > "$BOOTSTRAP_VERSION_PATH"
1125     fi
1126
1127     say "Installing Python packages..."
1128     TEMP_DIR=$(TempDir)
1129     trap 'rm -rf "$TEMP_DIR"' EXIT
1130     # There is no $ interpolation due to quotes on starting heredoc delimiter.
1131     # -------------------------------------------------------------------------
1132     cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt"
1133 # This is the flattened list of packages certbot-auto installs.
1134 # To generate this, do (with docker and package hashin installed):
1135 # ```
1136 # letsencrypt-auto-source/rebuild_dependencies.py \
1137 #   letsencrypt-auto-source/pieces/dependency-requirements.txt
1138 # ```
1139 # If you want to update a single dependency, run commands similar to these:
1140 # ```
1141 # pip install hashin
1142 # hashin -r dependency-requirements.txt cryptography==1.5.2
1143 # ```
1144 ConfigArgParse==0.14.0 \
1145     --hash=sha256:2e2efe2be3f90577aca9415e32cb629aa2ecd92078adbe27b53a03e53ff12e91
1146 asn1crypto==0.24.0 \
1147     --hash=sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87 \
1148     --hash=sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49
1149 certifi==2019.6.16 \
1150     --hash=sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939 \
1151     --hash=sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695
1152 cffi==1.12.3 \
1153     --hash=sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774 \
1154     --hash=sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d \
1155     --hash=sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90 \
1156     --hash=sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b \
1157     --hash=sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63 \
1158     --hash=sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45 \
1159     --hash=sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25 \
1160     --hash=sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3 \
1161     --hash=sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b \
1162     --hash=sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647 \
1163     --hash=sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016 \
1164     --hash=sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4 \
1165     --hash=sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb \
1166     --hash=sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753 \
1167     --hash=sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7 \
1168     --hash=sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9 \
1169     --hash=sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f \
1170     --hash=sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8 \
1171     --hash=sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f \
1172     --hash=sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc \
1173     --hash=sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42 \
1174     --hash=sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3 \
1175     --hash=sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909 \
1176     --hash=sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45 \
1177     --hash=sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d \
1178     --hash=sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512 \
1179     --hash=sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff \
1180     --hash=sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201
1181 chardet==3.0.4 \
1182     --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
1183     --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
1184 configobj==5.0.6 \
1185     --hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
1186 cryptography==2.7 \
1187     --hash=sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c \
1188     --hash=sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643 \
1189     --hash=sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216 \
1190     --hash=sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799 \
1191     --hash=sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a \
1192     --hash=sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9 \
1193     --hash=sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc \
1194     --hash=sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8 \
1195     --hash=sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53 \
1196     --hash=sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1 \
1197     --hash=sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609 \
1198     --hash=sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292 \
1199     --hash=sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e \
1200     --hash=sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6 \
1201     --hash=sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed \
1202     --hash=sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d
1203 distro==1.4.0 \
1204     --hash=sha256:362dde65d846d23baee4b5c058c8586f219b5a54be1cf5fc6ff55c4578392f57 \
1205     --hash=sha256:eedf82a470ebe7d010f1872c17237c79ab04097948800029994fa458e52fb4b4
1206 enum34==1.1.6 \
1207     --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
1208     --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
1209     --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
1210     --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1
1211 funcsigs==1.0.2 \
1212     --hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \
1213     --hash=sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50
1214 future==0.17.1 \
1215     --hash=sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8
1216 idna==2.8 \
1217     --hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \
1218     --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
1219 ipaddress==1.0.22 \
1220     --hash=sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794 \
1221     --hash=sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c
1222 josepy==1.2.0 \
1223     --hash=sha256:8ea15573203f28653c00f4ac0142520777b1c59d9eddd8da3f256c6ba3cac916 \
1224     --hash=sha256:9cec9a839fe9520f0420e4f38e7219525daccce4813296627436fe444cd002d3
1225 mock==1.3.0 \
1226     --hash=sha256:1e247dbecc6ce057299eb7ee019ad68314bb93152e81d9a6110d35f4d5eca0f6 \
1227     --hash=sha256:3f573a18be94de886d1191f27c168427ef693e8dcfcecf95b170577b2eb69cbb
1228 parsedatetime==2.4 \
1229     --hash=sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b \
1230     --hash=sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094
1231 pbr==5.4.2 \
1232     --hash=sha256:56e52299170b9492513c64be44736d27a512fa7e606f21942160b68ce510b4bc \
1233     --hash=sha256:9b321c204a88d8ab5082699469f52cc94c5da45c51f114113d01b3d993c24cdf
1234 pyOpenSSL==19.0.0 \
1235     --hash=sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200 \
1236     --hash=sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
1237 pyRFC3339==1.1 \
1238     --hash=sha256:67196cb83b470709c580bb4738b83165e67c6cc60e1f2e4f286cfcb402a926f4 \
1239     --hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
1240 pycparser==2.19 \
1241     --hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
1242 pyparsing==2.4.2 \
1243     --hash=sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80 \
1244     --hash=sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4
1245 python-augeas==0.5.0 \
1246     --hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2
1247 pytz==2019.2 \
1248     --hash=sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32 \
1249     --hash=sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7
1250 requests==2.21.0 \
1251     --hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
1252     --hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b
1253 requests-toolbelt==0.9.1 \
1254     --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \
1255     --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0
1256 six==1.12.0 \
1257     --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
1258     --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
1259 urllib3==1.24.3 \
1260     --hash=sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4 \
1261     --hash=sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb
1262 zope.component==4.5 \
1263     --hash=sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55 \
1264     --hash=sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4
1265 zope.deferredimport==4.3.1 \
1266     --hash=sha256:57b2345e7b5eef47efcd4f634ff16c93e4265de3dcf325afc7315ade48d909e1 \
1267     --hash=sha256:9a0c211df44aa95f1c4e6d2626f90b400f56989180d3ef96032d708da3d23e0a
1268 zope.deprecation==4.4.0 \
1269     --hash=sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df \
1270     --hash=sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113
1271 zope.event==4.4 \
1272     --hash=sha256:69c27debad9bdacd9ce9b735dad382142281ac770c4a432b533d6d65c4614bcf \
1273     --hash=sha256:d8e97d165fd5a0997b45f5303ae11ea3338becfe68c401dd88ffd2113fe5cae7
1274 zope.hookable==4.2.0 \
1275     --hash=sha256:22886e421234e7e8cedc21202e1d0ab59960e40a47dd7240e9659a2d82c51370 \
1276     --hash=sha256:39912f446e45b4e1f1951b5ffa2d5c8b074d25727ec51855ae9eab5408f105ab \
1277     --hash=sha256:3adb7ea0871dbc56b78f62c4f5c024851fc74299f4f2a95f913025b076cde220 \
1278     --hash=sha256:3d7c4b96341c02553d8b8d71065a9366ef67e6c6feca714f269894646bb8268b \
1279     --hash=sha256:4e826a11a529ed0464ffcecf34b0b7bd1b4928dd5848c5c61bedd7833e8f4801 \
1280     --hash=sha256:700d68cc30728de1c4c62088a981c6daeaefdf20a0d81995d2c0b7f442c5f88c \
1281     --hash=sha256:77c82a430cedfbf508d1aa406b2f437363c24fa90c73f577ead0fb5295749b83 \
1282     --hash=sha256:c1df3929a3666fc5a0c80d60a0c1e6f6ef97c7f6ed2f1b7cf49f3e6f3d4dde15 \
1283     --hash=sha256:dba8b2dd2cd41cb5f37bfa3f3d82721b8ae10e492944e48ddd90a439227f2893 \
1284     --hash=sha256:f492540305b15b5591bd7195d61f28946bb071de071cee5d68b6b8414da90fd2
1285 zope.interface==4.6.0 \
1286     --hash=sha256:086707e0f413ff8800d9c4bc26e174f7ee4c9c8b0302fbad68d083071822316c \
1287     --hash=sha256:1157b1ec2a1f5bf45668421e3955c60c610e31913cc695b407a574efdbae1f7b \
1288     --hash=sha256:11ebddf765bff3bbe8dbce10c86884d87f90ed66ee410a7e6c392086e2c63d02 \
1289     --hash=sha256:14b242d53f6f35c2d07aa2c0e13ccb710392bcd203e1b82a1828d216f6f6b11f \
1290     --hash=sha256:1b3d0dcabc7c90b470e59e38a9acaa361be43b3a6ea644c0063951964717f0e5 \
1291     --hash=sha256:20a12ab46a7e72b89ce0671e7d7a6c3c1ca2c2766ac98112f78c5bddaa6e4375 \
1292     --hash=sha256:298f82c0ab1b182bd1f34f347ea97dde0fffb9ecf850ecf7f8904b8442a07487 \
1293     --hash=sha256:2f6175722da6f23dbfc76c26c241b67b020e1e83ec7fe93c9e5d3dd18667ada2 \
1294     --hash=sha256:3b877de633a0f6d81b600624ff9137312d8b1d0f517064dfc39999352ab659f0 \
1295     --hash=sha256:4265681e77f5ac5bac0905812b828c9fe1ce80c6f3e3f8574acfb5643aeabc5b \
1296     --hash=sha256:550695c4e7313555549aa1cdb978dc9413d61307531f123558e438871a883d63 \
1297     --hash=sha256:5f4d42baed3a14c290a078e2696c5f565501abde1b2f3f1a1c0a94fbf6fbcc39 \
1298     --hash=sha256:62dd71dbed8cc6a18379700701d959307823b3b2451bdc018594c48956ace745 \
1299     --hash=sha256:7040547e5b882349c0a2cc9b50674b1745db551f330746af434aad4f09fba2cc \
1300     --hash=sha256:7e099fde2cce8b29434684f82977db4e24f0efa8b0508179fce1602d103296a2 \
1301     --hash=sha256:7e5c9a5012b2b33e87980cee7d1c82412b2ebabcb5862d53413ba1a2cfde23aa \
1302     --hash=sha256:81295629128f929e73be4ccfdd943a0906e5fe3cdb0d43ff1e5144d16fbb52b1 \
1303     --hash=sha256:95cc574b0b83b85be9917d37cd2fad0ce5a0d21b024e1a5804d044aabea636fc \
1304     --hash=sha256:968d5c5702da15c5bf8e4a6e4b67a4d92164e334e9c0b6acf080106678230b98 \
1305     --hash=sha256:9e998ba87df77a85c7bed53240a7257afe51a07ee6bc3445a0bf841886da0b97 \
1306     --hash=sha256:a0c39e2535a7e9c195af956610dba5a1073071d2d85e9d2e5d789463f63e52ab \
1307     --hash=sha256:a15e75d284178afe529a536b0e8b28b7e107ef39626a7809b4ee64ff3abc9127 \
1308     --hash=sha256:a6a6ff82f5f9b9702478035d8f6fb6903885653bff7ec3a1e011edc9b1a7168d \
1309     --hash=sha256:b639f72b95389620c1f881d94739c614d385406ab1d6926a9ffe1c8abbea23fe \
1310     --hash=sha256:bad44274b151d46619a7567010f7cde23a908c6faa84b97598fd2f474a0c6891 \
1311     --hash=sha256:bbcef00d09a30948756c5968863316c949d9cedbc7aabac5e8f0ffbdb632e5f1 \
1312     --hash=sha256:d788a3999014ddf416f2dc454efa4a5dbeda657c6aba031cf363741273804c6b \
1313     --hash=sha256:eed88ae03e1ef3a75a0e96a55a99d7937ed03e53d0cffc2451c208db445a2966 \
1314     --hash=sha256:f99451f3a579e73b5dd58b1b08d1179791d49084371d9a47baad3b22417f0317
1315 zope.proxy==4.3.2 \
1316     --hash=sha256:320a7619992e42142549ebf61e14ce27683b4d14b0cbc45f7c037ba64edb560c \
1317     --hash=sha256:824d4dbabbb7deb84f25fdb96ea1eeca436a1802c3c8d323b3eb4ac9d527d41c \
1318     --hash=sha256:8a32eb9c94908f3544da2dae3f4a9e6961d78819b88ac6b6f4a51cee2d65f4a0 \
1319     --hash=sha256:96265fd3bc3ea646f98482e16307a69de21402eeaaaaf4b841c1161ac2f71bb0 \
1320     --hash=sha256:ab6d6975d9c51c13cac828ff03168de21fb562b0664c59bcdc4a4b10f39a5b17 \
1321     --hash=sha256:af10cb772391772463f65a58348e2de5ecc06693c16d2078be276dc068bcbb54 \
1322     --hash=sha256:b8fd3a3de3f7b6452775e92af22af5977b17b69ac86a38a3ddfe870e40a0d05f \
1323     --hash=sha256:bb7088f1bed3b8214284a5e425dc23da56f2f28e8815b7580bfed9e245b6c0b6 \
1324     --hash=sha256:bc29b3665eac34f14c4aef5224bef045efcfb1a7d12d78c8685858de5fbf21c0 \
1325     --hash=sha256:c39fa6a159affeae5fe31b49d9f5b12bd674fe77271a9a324408b271440c50a7 \
1326     --hash=sha256:e946a036ac5b9f897e986ac9dc950a34cffc857d88eae6727b8434fbc4752366
1327
1328 # Contains the requirements for the letsencrypt package.
1329 #
1330 # Since the letsencrypt package depends on certbot and using pip with hashes
1331 # requires that all installed packages have hashes listed, this allows
1332 # dependency-requirements.txt to be used without requiring a hash for a
1333 # (potentially unreleased) Certbot package.
1334
1335 letsencrypt==0.7.0 \
1336     --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
1337     --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
1338
1339 certbot==0.37.2 \
1340     --hash=sha256:8f6f0097fb2aac64f13e5d6974781ac85a051d84a6cb3f4d79c6b75c5ea451b8 \
1341     --hash=sha256:e454368aa8d62559c673091b511319c130c8e0ea1c4dfa314ed7bdc91dd96ef5
1342 acme==0.37.2 \
1343     --hash=sha256:5666ba927a9e7bf3f9ed5a268bd5acf627b5838fb409e8401f05d2aaaee188ba \
1344     --hash=sha256:88798fae3bc692397db79c66930bd02fcaba8a6b1fba9a62f111dda42cc47f5c
1345 certbot-apache==0.37.2 \
1346     --hash=sha256:e3ae7057f727506ab3796095ed66ca083f4e295d06f209ab96d2a3f37dea51b9 \
1347     --hash=sha256:4cb44d1a7c56176a84446a11412c561479ed0fed19848632e61f104dbf6a3031
1348 certbot-nginx==0.37.2 \
1349     --hash=sha256:a92dffdf3daca97db5d7ae2287e505110c3fa01c035b9356abb2ef9fa32e8695 \
1350     --hash=sha256:404f7b5b7611f0dce8773739170f306e94a59b69528cb74337e7f354936ac061
1351
1352 UNLIKELY_EOF
1353     # -------------------------------------------------------------------------
1354     cat << "UNLIKELY_EOF" > "$TEMP_DIR/pipstrap.py"
1355 #!/usr/bin/env python
1356 """A small script that can act as a trust root for installing pip >=8
1357 Embed this in your project, and your VCS checkout is all you have to trust. In
1358 a post-peep era, this lets you claw your way to a hash-checking version of pip,
1359 with which you can install the rest of your dependencies safely. All it assumes
1360 is Python 2.6 or better and *some* version of pip already installed. If
1361 anything goes wrong, it will exit with a non-zero status code.
1362 """
1363 # This is here so embedded copies are MIT-compliant:
1364 # Copyright (c) 2016 Erik Rose
1365 #
1366 # Permission is hereby granted, free of charge, to any person obtaining a copy
1367 # of this software and associated documentation files (the "Software"), to
1368 # deal in the Software without restriction, including without limitation the
1369 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
1370 # sell copies of the Software, and to permit persons to whom the Software is
1371 # furnished to do so, subject to the following conditions:
1372 #
1373 # The above copyright notice and this permission notice shall be included in
1374 # all copies or substantial portions of the Software.
1375 from __future__ import print_function
1376 from distutils.version import StrictVersion
1377 from hashlib import sha256
1378 from os import environ
1379 from os.path import join
1380 from shutil import rmtree
1381 try:
1382     from subprocess import check_output
1383 except ImportError:
1384     from subprocess import CalledProcessError, PIPE, Popen
1385
1386     def check_output(*popenargs, **kwargs):
1387         if 'stdout' in kwargs:
1388             raise ValueError('stdout argument not allowed, it will be '
1389                              'overridden.')
1390         process = Popen(stdout=PIPE, *popenargs, **kwargs)
1391         output, unused_err = process.communicate()
1392         retcode = process.poll()
1393         if retcode:
1394             cmd = kwargs.get("args")
1395             if cmd is None:
1396                 cmd = popenargs[0]
1397             raise CalledProcessError(retcode, cmd)
1398         return output
1399 import sys
1400 from tempfile import mkdtemp
1401 try:
1402     from urllib2 import build_opener, HTTPHandler, HTTPSHandler
1403 except ImportError:
1404     from urllib.request import build_opener, HTTPHandler, HTTPSHandler
1405 try:
1406     from urlparse import urlparse
1407 except ImportError:
1408     from urllib.parse import urlparse  # 3.4
1409
1410
1411 __version__ = 1, 5, 1
1412 PIP_VERSION = '9.0.1'
1413 DEFAULT_INDEX_BASE = 'https://pypi.python.org'
1414
1415
1416 # wheel has a conditional dependency on argparse:
1417 maybe_argparse = (
1418     [('18/dd/e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/'
1419       'argparse-1.4.0.tar.gz',
1420       '62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')]
1421     if sys.version_info < (2, 7, 0) else [])
1422
1423
1424 PACKAGES = maybe_argparse + [
1425     # Pip has no dependencies, as it vendors everything:
1426     ('11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/'
1427      'pip-{0}.tar.gz'.format(PIP_VERSION),
1428      '09f243e1a7b461f654c26a725fa373211bb7ff17a9300058b205c61658ca940d'),
1429     # This version of setuptools has only optional dependencies:
1430     ('37/1b/b25507861991beeade31473868463dad0e58b1978c209de27384ae541b0b/'
1431      'setuptools-40.6.3.zip',
1432      '3b474dad69c49f0d2d86696b68105f3a6f195f7ab655af12ef9a9c326d2b08f8'),
1433     ('c9/1d/bd19e691fd4cfe908c76c429fe6e4436c9e83583c4414b54f6c85471954a/'
1434      'wheel-0.29.0.tar.gz',
1435      '1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648')
1436 ]
1437
1438
1439 class HashError(Exception):
1440     def __str__(self):
1441         url, path, actual, expected = self.args
1442         return ('{url} did not match the expected hash {expected}. Instead, '
1443                 'it was {actual}. The file (left at {path}) may have been '
1444                 'tampered with.'.format(**locals()))
1445
1446
1447 def hashed_download(url, temp, digest):
1448     """Download ``url`` to ``temp``, make sure it has the SHA-256 ``digest``,
1449     and return its path."""
1450     # Based on pip 1.4.1's URLOpener but with cert verification removed. Python
1451     # >=2.7.9 verifies HTTPS certs itself, and, in any case, the cert
1452     # authenticity has only privacy (not arbitrary code execution)
1453     # implications, since we're checking hashes.
1454     def opener(using_https=True):
1455         opener = build_opener(HTTPSHandler())
1456         if using_https:
1457             # Strip out HTTPHandler to prevent MITM spoof:
1458             for handler in opener.handlers:
1459                 if isinstance(handler, HTTPHandler):
1460                     opener.handlers.remove(handler)
1461         return opener
1462
1463     def read_chunks(response, chunk_size):
1464         while True:
1465             chunk = response.read(chunk_size)
1466             if not chunk:
1467                 break
1468             yield chunk
1469
1470     parsed_url = urlparse(url)
1471     response = opener(using_https=parsed_url.scheme == 'https').open(url)
1472     path = join(temp, parsed_url.path.split('/')[-1])
1473     actual_hash = sha256()
1474     with open(path, 'wb') as file:
1475         for chunk in read_chunks(response, 4096):
1476             file.write(chunk)
1477             actual_hash.update(chunk)
1478
1479     actual_digest = actual_hash.hexdigest()
1480     if actual_digest != digest:
1481         raise HashError(url, path, actual_digest, digest)
1482     return path
1483
1484
1485 def get_index_base():
1486     """Return the URL to the dir containing the "packages" folder.
1487     Try to wring something out of PIP_INDEX_URL, if set. Hack "/simple" off the
1488     end if it's there; that is likely to give us the right dir.
1489     """
1490     env_var = environ.get('PIP_INDEX_URL', '').rstrip('/')
1491     if env_var:
1492         SIMPLE = '/simple'
1493         if env_var.endswith(SIMPLE):
1494             return env_var[:-len(SIMPLE)]
1495         else:
1496             return env_var
1497     else:
1498         return DEFAULT_INDEX_BASE
1499
1500
1501 def main():
1502     python = sys.executable or 'python'
1503     pip_version = StrictVersion(check_output([python, '-m', 'pip', '--version'])
1504                                 .decode('utf-8').split()[1])
1505     has_pip_cache = pip_version >= StrictVersion('6.0')
1506     index_base = get_index_base()
1507     temp = mkdtemp(prefix='pipstrap-')
1508     try:
1509         downloads = [hashed_download(index_base + '/packages/' + path,
1510                                      temp,
1511                                      digest)
1512                      for path, digest in PACKAGES]
1513         # Calling pip as a module is the preferred way to avoid problems about pip self-upgrade.
1514         command = [python, '-m', 'pip', 'install', '--no-index', '--no-deps', '-U']
1515         # Disable cache since it is not used and it otherwise sometimes throws permission warnings:
1516         command.extend(['--no-cache-dir'] if has_pip_cache else [])
1517         command.extend(downloads)
1518         check_output(command)
1519     except HashError as exc:
1520         print(exc)
1521     except Exception:
1522         rmtree(temp)
1523         raise
1524     else:
1525         rmtree(temp)
1526         return 0
1527     return 1
1528
1529
1530 if __name__ == '__main__':
1531     sys.exit(main())
1532
1533 UNLIKELY_EOF
1534     # -------------------------------------------------------------------------
1535     # Set PATH so pipstrap upgrades the right (v)env:
1536     PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py"
1537     set +e
1538     if [ "$VERBOSE" = 1 ]; then
1539       "$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt"
1540     else
1541       PIP_OUT=`"$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1`
1542     fi
1543     PIP_STATUS=$?
1544     set -e
1545     if [ "$PIP_STATUS" != 0 ]; then
1546       # Report error. (Otherwise, be quiet.)
1547       error "Had a problem while installing Python packages."
1548       if [ "$VERBOSE" != 1 ]; then
1549         error
1550         error "pip prints the following errors: "
1551         error "====================================================="
1552         error "$PIP_OUT"
1553         error "====================================================="
1554         error
1555         error "Certbot has problem setting up the virtual environment."
1556
1557         if `echo $PIP_OUT | grep -q Killed` || `echo $PIP_OUT | grep -q "allocate memory"` ; then
1558           error
1559           error "Based on your pip output, the problem can likely be fixed by "
1560           error "increasing the available memory."
1561         else
1562           error
1563           error "We were not be able to guess the right solution from your pip "
1564           error "output."
1565         fi
1566
1567         error
1568         error "Consult https://certbot.eff.org/docs/install.html#problems-with-python-virtual-environment"
1569         error "for possible solutions."
1570         error "You may also find some support resources at https://certbot.eff.org/support/ ."
1571       fi
1572       rm -rf "$VENV_PATH"
1573       exit 1
1574     fi
1575
1576     if [ -d "$OLD_VENV_PATH" -a ! -L "$OLD_VENV_PATH" ]; then
1577       rm -rf "$OLD_VENV_PATH"
1578       ln -s "$VENV_PATH" "$OLD_VENV_PATH"
1579     fi
1580
1581     say "Installation succeeded."
1582   fi
1583
1584   if [ "$INSTALL_ONLY" = 1 ]; then
1585     say "Certbot is installed."
1586     exit 0
1587   fi
1588
1589   "$VENV_BIN/letsencrypt" "$@"
1590
1591 else
1592   # Phase 1: Upgrade certbot-auto if necessary, then self-invoke.
1593   #
1594   # Each phase checks the version of only the thing it is responsible for
1595   # upgrading. Phase 1 checks the version of the latest release of
1596   # certbot-auto (which is always the same as that of the certbot
1597   # package). Phase 2 checks the version of the locally installed certbot.
1598   export PHASE_1_VERSION="$LE_AUTO_VERSION"
1599
1600   if [ ! -f "$VENV_BIN/letsencrypt" ]; then
1601     if ! OldVenvExists; then
1602       if [ "$HELP" = 1 ]; then
1603         echo "$USAGE"
1604         exit 0
1605       fi
1606       # If it looks like we've never bootstrapped before, bootstrap:
1607       Bootstrap
1608     fi
1609   fi
1610   if [ "$OS_PACKAGES_ONLY" = 1 ]; then
1611     say "OS packages installed."
1612     exit 0
1613   fi
1614
1615   DeterminePythonVersion "NOCRASH"
1616   # Don't warn about file permissions if the user disabled the check or we
1617   # can't find an up-to-date Python.
1618   if [ "$PYVER" -ge "$MIN_PYVER" -a "$NO_PERMISSIONS_CHECK" != 1 ]; then
1619     # If the script fails for some reason, don't break certbot-auto.
1620     set +e
1621     # Suppress unexpected error output.
1622     CHECK_PERM_OUT=$(CheckPathPermissions "$LE_PYTHON" "$0" 2>/dev/null)
1623     CHECK_PERM_STATUS="$?"
1624     set -e
1625     # Only print output if the script ran successfully and it actually produced
1626     # output. The latter check resolves
1627     # https://github.com/certbot/certbot/issues/7012.
1628     if [ "$CHECK_PERM_STATUS" = 0 -a -n "$CHECK_PERM_OUT" ]; then
1629       error "$CHECK_PERM_OUT"
1630     fi
1631   fi
1632
1633   if [ "$NO_SELF_UPGRADE" != 1 ]; then
1634     TEMP_DIR=$(TempDir)
1635     trap 'rm -rf "$TEMP_DIR"' EXIT
1636     # ---------------------------------------------------------------------------
1637     cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py"
1638 """Do downloading and JSON parsing without additional dependencies. ::
1639
1640     # Print latest released version of LE to stdout:
1641     python fetch.py --latest-version
1642
1643     # Download letsencrypt-auto script from git tag v1.2.3 into the folder I'm
1644     # in, and make sure its signature verifies:
1645     python fetch.py --le-auto-script v1.2.3
1646
1647 On failure, return non-zero.
1648
1649 """
1650
1651 from __future__ import print_function, unicode_literals
1652
1653 from distutils.version import LooseVersion
1654 from json import loads
1655 from os import devnull, environ
1656 from os.path import dirname, join
1657 import re
1658 import ssl
1659 from subprocess import check_call, CalledProcessError
1660 from sys import argv, exit
1661 try:
1662     from urllib2 import build_opener, HTTPHandler, HTTPSHandler
1663     from urllib2 import HTTPError, URLError
1664 except ImportError:
1665     from urllib.request import build_opener, HTTPHandler, HTTPSHandler
1666     from urllib.error import HTTPError, URLError
1667
1668 PUBLIC_KEY = environ.get('LE_AUTO_PUBLIC_KEY', """-----BEGIN PUBLIC KEY-----
1669 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6MR8W/galdxnpGqBsYbq
1670 OzQb2eyW15YFjDDEMI0ZOzt8f504obNs920lDnpPD2/KqgsfjOgw2K7xWDJIj/18
1671 xUvWPk3LDkrnokNiRkA3KOx3W6fHycKL+zID7zy+xZYBuh2fLyQtWV1VGQ45iNRp
1672 9+Zo7rH86cdfgkdnWTlNSHyTLW9NbXvyv/E12bppPcEvgCTAQXgnDVJ0/sqmeiij
1673 n9tTFh03aM+R2V/21h8aTraAS24qiPCz6gkmYGC8yr6mglcnNoYbsLNYZ69zF1XH
1674 cXPduCPdPdfLlzVlKK1/U7hkA28eG3BIAMh6uJYBRJTpiGgaGdPd7YekUB8S6cy+
1675 CQIDAQAB
1676 -----END PUBLIC KEY-----
1677 """)
1678
1679 class ExpectedError(Exception):
1680     """A novice-readable exception that also carries the original exception for
1681     debugging"""
1682
1683
1684 class HttpsGetter(object):
1685     def __init__(self):
1686         """Build an HTTPS opener."""
1687         # Based on pip 1.4.1's URLOpener
1688         # This verifies certs on only Python >=2.7.9, and when NO_CERT_VERIFY isn't set.
1689         if environ.get('NO_CERT_VERIFY') == '1' and hasattr(ssl, 'SSLContext'):
1690             self._opener = build_opener(HTTPSHandler(context=cert_none_context()))
1691         else:
1692             self._opener = build_opener(HTTPSHandler())
1693         # Strip out HTTPHandler to prevent MITM spoof:
1694         for handler in self._opener.handlers:
1695             if isinstance(handler, HTTPHandler):
1696                 self._opener.handlers.remove(handler)
1697
1698     def get(self, url):
1699         """Return the document contents pointed to by an HTTPS URL.
1700
1701         If something goes wrong (404, timeout, etc.), raise ExpectedError.
1702
1703         """
1704         try:
1705             # socket module docs say default timeout is None: that is, no
1706             # timeout
1707             return self._opener.open(url, timeout=30).read()
1708         except (HTTPError, IOError) as exc:
1709             raise ExpectedError("Couldn't download %s." % url, exc)
1710
1711
1712 def write(contents, dir, filename):
1713     """Write something to a file in a certain directory."""
1714     with open(join(dir, filename), 'wb') as file:
1715         file.write(contents)
1716
1717
1718 def latest_stable_version(get):
1719     """Return the latest stable release of letsencrypt."""
1720     metadata = loads(get(
1721         environ.get('LE_AUTO_JSON_URL',
1722                     'https://pypi.python.org/pypi/certbot/json')).decode('UTF-8'))
1723     # metadata['info']['version'] actually returns the latest of any kind of
1724     # release release, contrary to https://wiki.python.org/moin/PyPIJSON.
1725     # The regex is a sufficient regex for picking out prereleases for most
1726     # packages, LE included.
1727     return str(max(LooseVersion(r) for r
1728                    in metadata['releases'].keys()
1729                    if re.match('^[0-9.]+$', r)))
1730
1731
1732 def verified_new_le_auto(get, tag, temp_dir):
1733     """Return the path to a verified, up-to-date letsencrypt-auto script.
1734
1735     If the download's signature does not verify or something else goes wrong
1736     with the verification process, raise ExpectedError.
1737
1738     """
1739     le_auto_dir = environ.get(
1740         'LE_AUTO_DIR_TEMPLATE',
1741         'https://raw.githubusercontent.com/certbot/certbot/%s/'
1742         'letsencrypt-auto-source/') % tag
1743     write(get(le_auto_dir + 'letsencrypt-auto'), temp_dir, 'letsencrypt-auto')
1744     write(get(le_auto_dir + 'letsencrypt-auto.sig'), temp_dir, 'letsencrypt-auto.sig')
1745     write(PUBLIC_KEY.encode('UTF-8'), temp_dir, 'public_key.pem')
1746     try:
1747         with open(devnull, 'w') as dev_null:
1748             check_call(['openssl', 'dgst', '-sha256', '-verify',
1749                         join(temp_dir, 'public_key.pem'),
1750                         '-signature',
1751                         join(temp_dir, 'letsencrypt-auto.sig'),
1752                         join(temp_dir, 'letsencrypt-auto')],
1753                        stdout=dev_null,
1754                        stderr=dev_null)
1755     except CalledProcessError as exc:
1756         raise ExpectedError("Couldn't verify signature of downloaded "
1757                             "certbot-auto.", exc)
1758
1759
1760 def cert_none_context():
1761     """Create a SSLContext object to not check hostname."""
1762     # PROTOCOL_TLS isn't available before 2.7.13 but this code is for 2.7.9+, so use this.
1763     context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1764     context.verify_mode = ssl.CERT_NONE
1765     return context
1766
1767
1768 def main():
1769     get = HttpsGetter().get
1770     flag = argv[1]
1771     try:
1772         if flag == '--latest-version':
1773             print(latest_stable_version(get))
1774         elif flag == '--le-auto-script':
1775             tag = argv[2]
1776             verified_new_le_auto(get, tag, dirname(argv[0]))
1777     except ExpectedError as exc:
1778         print(exc.args[0], exc.args[1])
1779         return 1
1780     else:
1781         return 0
1782
1783
1784 if __name__ == '__main__':
1785     exit(main())
1786
1787 UNLIKELY_EOF
1788     # ---------------------------------------------------------------------------
1789     if [ "$PYVER" -lt "$MIN_PYVER" ]; then
1790       error "WARNING: couldn't find Python $MIN_PYTHON_VERSION+ to check for updates."
1791     elif ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
1792       error "WARNING: unable to check for updates."
1793     fi
1794
1795     LE_VERSION_STATE=`CompareVersions "$LE_PYTHON" "$LE_AUTO_VERSION" "$REMOTE_VERSION"`
1796     if [ "$LE_VERSION_STATE" = "UNOFFICIAL" ]; then
1797       say "Unofficial certbot-auto version detected, self-upgrade is disabled: $LE_AUTO_VERSION"
1798     elif [ "$LE_VERSION_STATE" = "OUTDATED" ]; then
1799       say "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
1800
1801       # Now we drop into Python so we don't have to install even more
1802       # dependencies (curl, etc.), for better flow control, and for the option of
1803       # future Windows compatibility.
1804       "$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION"
1805
1806       # Install new copy of certbot-auto.
1807       # TODO: Deal with quotes in pathnames.
1808       say "Replacing certbot-auto..."
1809       # Clone permissions with cp. chmod and chown don't have a --reference
1810       # option on macOS or BSD, and stat -c on Linux is stat -f on macOS and BSD:
1811       cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
1812       cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
1813       # Using mv rather than cp leaves the old file descriptor pointing to the
1814       # original copy so the shell can continue to read it unmolested. mv across
1815       # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the
1816       # cp is unlikely to fail if the rm doesn't.
1817       mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
1818     fi  # A newer version is available.
1819   fi  # Self-upgrading is allowed.
1820
1821   RerunWithArgs --le-auto-phase2 "$@"
1822 fi