5e65c2619217f9b131b3659c43f54b2245630264
[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-sources/pieces/dependency-requirements.txt
1138 # ```
1139 ConfigArgParse==0.14.0 \
1140     --hash=sha256:2e2efe2be3f90577aca9415e32cb629aa2ecd92078adbe27b53a03e53ff12e91
1141 asn1crypto==0.24.0 \
1142     --hash=sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87 \
1143     --hash=sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49
1144 certifi==2019.3.9 \
1145     --hash=sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5 \
1146     --hash=sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae
1147 cffi==1.12.2 \
1148     --hash=sha256:00b97afa72c233495560a0793cdc86c2571721b4271c0667addc83c417f3d90f \
1149     --hash=sha256:0ba1b0c90f2124459f6966a10c03794082a2f3985cd699d7d63c4a8dae113e11 \
1150     --hash=sha256:0bffb69da295a4fc3349f2ec7cbe16b8ba057b0a593a92cbe8396e535244ee9d \
1151     --hash=sha256:21469a2b1082088d11ccd79dd84157ba42d940064abbfa59cf5f024c19cf4891 \
1152     --hash=sha256:2e4812f7fa984bf1ab253a40f1f4391b604f7fc424a3e21f7de542a7f8f7aedf \
1153     --hash=sha256:2eac2cdd07b9049dd4e68449b90d3ef1adc7c759463af5beb53a84f1db62e36c \
1154     --hash=sha256:2f9089979d7456c74d21303c7851f158833d48fb265876923edcb2d0194104ed \
1155     --hash=sha256:3dd13feff00bddb0bd2d650cdb7338f815c1789a91a6f68fdc00e5c5ed40329b \
1156     --hash=sha256:4065c32b52f4b142f417af6f33a5024edc1336aa845b9d5a8d86071f6fcaac5a \
1157     --hash=sha256:51a4ba1256e9003a3acf508e3b4f4661bebd015b8180cc31849da222426ef585 \
1158     --hash=sha256:59888faac06403767c0cf8cfb3f4a777b2939b1fbd9f729299b5384f097f05ea \
1159     --hash=sha256:59c87886640574d8b14910840327f5cd15954e26ed0bbd4e7cef95fa5aef218f \
1160     --hash=sha256:610fc7d6db6c56a244c2701575f6851461753c60f73f2de89c79bbf1cc807f33 \
1161     --hash=sha256:70aeadeecb281ea901bf4230c6222af0248c41044d6f57401a614ea59d96d145 \
1162     --hash=sha256:71e1296d5e66c59cd2c0f2d72dc476d42afe02aeddc833d8e05630a0551dad7a \
1163     --hash=sha256:8fc7a49b440ea752cfdf1d51a586fd08d395ff7a5d555dc69e84b1939f7ddee3 \
1164     --hash=sha256:9b5c2afd2d6e3771d516045a6cfa11a8da9a60e3d128746a7fe9ab36dfe7221f \
1165     --hash=sha256:9c759051ebcb244d9d55ee791259ddd158188d15adee3c152502d3b69005e6bd \
1166     --hash=sha256:b4d1011fec5ec12aa7cc10c05a2f2f12dfa0adfe958e56ae38dc140614035804 \
1167     --hash=sha256:b4f1d6332339ecc61275bebd1f7b674098a66fea11a00c84d1c58851e618dc0d \
1168     --hash=sha256:c030cda3dc8e62b814831faa4eb93dd9a46498af8cd1d5c178c2de856972fd92 \
1169     --hash=sha256:c2e1f2012e56d61390c0e668c20c4fb0ae667c44d6f6a2eeea5d7148dcd3df9f \
1170     --hash=sha256:c37c77d6562074452120fc6c02ad86ec928f5710fbc435a181d69334b4de1d84 \
1171     --hash=sha256:c8149780c60f8fd02752d0429246088c6c04e234b895c4a42e1ea9b4de8d27fb \
1172     --hash=sha256:cbeeef1dc3c4299bd746b774f019de9e4672f7cc666c777cd5b409f0b746dac7 \
1173     --hash=sha256:e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7 \
1174     --hash=sha256:e21162bf941b85c0cda08224dade5def9360f53b09f9f259adb85fc7dd0e7b35 \
1175     --hash=sha256:fb6934ef4744becbda3143d30c6604718871495a5e36c408431bf33d9c146889
1176 chardet==3.0.4 \
1177     --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
1178     --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
1179 configobj==5.0.6 \
1180     --hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
1181 cryptography==2.6.1 \
1182     --hash=sha256:066f815f1fe46020877c5983a7e747ae140f517f1b09030ec098503575265ce1 \
1183     --hash=sha256:210210d9df0afba9e000636e97810117dc55b7157c903a55716bb73e3ae07705 \
1184     --hash=sha256:26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6 \
1185     --hash=sha256:2afb83308dc5c5255149ff7d3fb9964f7c9ee3d59b603ec18ccf5b0a8852e2b1 \
1186     --hash=sha256:2db34e5c45988f36f7a08a7ab2b69638994a8923853dec2d4af121f689c66dc8 \
1187     --hash=sha256:409c4653e0f719fa78febcb71ac417076ae5e20160aec7270c91d009837b9151 \
1188     --hash=sha256:45a4f4cf4f4e6a55c8128f8b76b4c057027b27d4c67e3fe157fa02f27e37830d \
1189     --hash=sha256:48eab46ef38faf1031e58dfcc9c3e71756a1108f4c9c966150b605d4a1a7f659 \
1190     --hash=sha256:6b9e0ae298ab20d371fc26e2129fd683cfc0cfde4d157c6341722de645146537 \
1191     --hash=sha256:6c4778afe50f413707f604828c1ad1ff81fadf6c110cb669579dea7e2e98a75e \
1192     --hash=sha256:8c33fb99025d353c9520141f8bc989c2134a1f76bac6369cea060812f5b5c2bb \
1193     --hash=sha256:9873a1760a274b620a135054b756f9f218fa61ca030e42df31b409f0fb738b6c \
1194     --hash=sha256:9b069768c627f3f5623b1cbd3248c5e7e92aec62f4c98827059eed7053138cc9 \
1195     --hash=sha256:9e4ce27a507e4886efbd3c32d120db5089b906979a4debf1d5939ec01b9dd6c5 \
1196     --hash=sha256:acb424eaca214cb08735f1a744eceb97d014de6530c1ea23beb86d9c6f13c2ad \
1197     --hash=sha256:c8181c7d77388fe26ab8418bb088b1a1ef5fde058c6926790c8a0a3d94075a4a \
1198     --hash=sha256:d4afbb0840f489b60f5a580a41a1b9c3622e08ecb5eec8614d4fb4cd914c4460 \
1199     --hash=sha256:d9ed28030797c00f4bc43c86bf819266c76a5ea61d006cd4078a93ebf7da6bfd \
1200     --hash=sha256:e603aa7bb52e4e8ed4119a58a03b60323918467ef209e6ff9db3ac382e5cf2c6
1201 # Package enum34 needs to be explicitly limited to Python2.x, in order to avoid
1202 # certbot-auto failures on Python 3.6+ which enum34 doesn't support. See #5456.
1203 enum34==1.1.6 ; python_version < '3.4' \
1204     --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
1205     --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
1206     --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
1207     --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1
1208 funcsigs==1.0.2 \
1209     --hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \
1210     --hash=sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50
1211 future==0.17.1 \
1212     --hash=sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8
1213 idna==2.8 \
1214     --hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \
1215     --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
1216 ipaddress==1.0.22 \
1217     --hash=sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794 \
1218     --hash=sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c
1219 josepy==1.1.0 \
1220     --hash=sha256:1309a25aac3caeff5239729c58ff9b583f7d022ffdb1553406ddfc8e5b52b76e \
1221     --hash=sha256:fb5c62c77d26e04df29cb5ecd01b9ce69b6fcc9e521eb1ca193b7faa2afa7086
1222 mock==1.3.0 \
1223     --hash=sha256:1e247dbecc6ce057299eb7ee019ad68314bb93152e81d9a6110d35f4d5eca0f6 \
1224     --hash=sha256:3f573a18be94de886d1191f27c168427ef693e8dcfcecf95b170577b2eb69cbb
1225 parsedatetime==2.4 \
1226     --hash=sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b \
1227     --hash=sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094
1228 pbr==5.1.3 \
1229     --hash=sha256:8257baf496c8522437e8a6cfe0f15e00aedc6c0e0e7c9d55eeeeab31e0853843 \
1230     --hash=sha256:8c361cc353d988e4f5b998555c88098b9d5964c2e11acf7b0d21925a66bb5824
1231 pyOpenSSL==19.0.0 \
1232     --hash=sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200 \
1233     --hash=sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
1234 pyRFC3339==1.1 \
1235     --hash=sha256:67196cb83b470709c580bb4738b83165e67c6cc60e1f2e4f286cfcb402a926f4 \
1236     --hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
1237 pycparser==2.19 \
1238     --hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
1239 pyparsing==2.3.1 \
1240     --hash=sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a \
1241     --hash=sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3
1242 python-augeas==0.5.0 \
1243     --hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2
1244 pytz==2018.9 \
1245     --hash=sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9 \
1246     --hash=sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c
1247 requests==2.21.0 \
1248     --hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
1249     --hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b
1250 requests-toolbelt==0.9.1 \
1251     --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \
1252     --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0
1253 six==1.12.0 \
1254     --hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
1255     --hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
1256 urllib3==1.24.2 \
1257     --hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
1258     --hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3
1259 zope.component==4.5 \
1260     --hash=sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55 \
1261     --hash=sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4
1262 zope.deferredimport==4.3 \
1263     --hash=sha256:2ddef5a7ecfff132a2dd796253366ecf9748a446e30f1a0b3a636aec9d9c05c5 \
1264     --hash=sha256:4aae9cbacb2146cca58e62be0a914f0cec034d3b2d41135ea212ca8a96f4b5ec
1265 zope.deprecation==4.4.0 \
1266     --hash=sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df \
1267     --hash=sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113
1268 zope.event==4.4 \
1269     --hash=sha256:69c27debad9bdacd9ce9b735dad382142281ac770c4a432b533d6d65c4614bcf \
1270     --hash=sha256:d8e97d165fd5a0997b45f5303ae11ea3338becfe68c401dd88ffd2113fe5cae7
1271 zope.hookable==4.2.0 \
1272     --hash=sha256:22886e421234e7e8cedc21202e1d0ab59960e40a47dd7240e9659a2d82c51370 \
1273     --hash=sha256:39912f446e45b4e1f1951b5ffa2d5c8b074d25727ec51855ae9eab5408f105ab \
1274     --hash=sha256:3adb7ea0871dbc56b78f62c4f5c024851fc74299f4f2a95f913025b076cde220 \
1275     --hash=sha256:3d7c4b96341c02553d8b8d71065a9366ef67e6c6feca714f269894646bb8268b \
1276     --hash=sha256:4e826a11a529ed0464ffcecf34b0b7bd1b4928dd5848c5c61bedd7833e8f4801 \
1277     --hash=sha256:700d68cc30728de1c4c62088a981c6daeaefdf20a0d81995d2c0b7f442c5f88c \
1278     --hash=sha256:77c82a430cedfbf508d1aa406b2f437363c24fa90c73f577ead0fb5295749b83 \
1279     --hash=sha256:c1df3929a3666fc5a0c80d60a0c1e6f6ef97c7f6ed2f1b7cf49f3e6f3d4dde15 \
1280     --hash=sha256:dba8b2dd2cd41cb5f37bfa3f3d82721b8ae10e492944e48ddd90a439227f2893 \
1281     --hash=sha256:f492540305b15b5591bd7195d61f28946bb071de071cee5d68b6b8414da90fd2
1282 zope.interface==4.6.0 \
1283     --hash=sha256:086707e0f413ff8800d9c4bc26e174f7ee4c9c8b0302fbad68d083071822316c \
1284     --hash=sha256:1157b1ec2a1f5bf45668421e3955c60c610e31913cc695b407a574efdbae1f7b \
1285     --hash=sha256:11ebddf765bff3bbe8dbce10c86884d87f90ed66ee410a7e6c392086e2c63d02 \
1286     --hash=sha256:14b242d53f6f35c2d07aa2c0e13ccb710392bcd203e1b82a1828d216f6f6b11f \
1287     --hash=sha256:1b3d0dcabc7c90b470e59e38a9acaa361be43b3a6ea644c0063951964717f0e5 \
1288     --hash=sha256:20a12ab46a7e72b89ce0671e7d7a6c3c1ca2c2766ac98112f78c5bddaa6e4375 \
1289     --hash=sha256:298f82c0ab1b182bd1f34f347ea97dde0fffb9ecf850ecf7f8904b8442a07487 \
1290     --hash=sha256:2f6175722da6f23dbfc76c26c241b67b020e1e83ec7fe93c9e5d3dd18667ada2 \
1291     --hash=sha256:3b877de633a0f6d81b600624ff9137312d8b1d0f517064dfc39999352ab659f0 \
1292     --hash=sha256:4265681e77f5ac5bac0905812b828c9fe1ce80c6f3e3f8574acfb5643aeabc5b \
1293     --hash=sha256:550695c4e7313555549aa1cdb978dc9413d61307531f123558e438871a883d63 \
1294     --hash=sha256:5f4d42baed3a14c290a078e2696c5f565501abde1b2f3f1a1c0a94fbf6fbcc39 \
1295     --hash=sha256:62dd71dbed8cc6a18379700701d959307823b3b2451bdc018594c48956ace745 \
1296     --hash=sha256:7040547e5b882349c0a2cc9b50674b1745db551f330746af434aad4f09fba2cc \
1297     --hash=sha256:7e099fde2cce8b29434684f82977db4e24f0efa8b0508179fce1602d103296a2 \
1298     --hash=sha256:7e5c9a5012b2b33e87980cee7d1c82412b2ebabcb5862d53413ba1a2cfde23aa \
1299     --hash=sha256:81295629128f929e73be4ccfdd943a0906e5fe3cdb0d43ff1e5144d16fbb52b1 \
1300     --hash=sha256:95cc574b0b83b85be9917d37cd2fad0ce5a0d21b024e1a5804d044aabea636fc \
1301     --hash=sha256:968d5c5702da15c5bf8e4a6e4b67a4d92164e334e9c0b6acf080106678230b98 \
1302     --hash=sha256:9e998ba87df77a85c7bed53240a7257afe51a07ee6bc3445a0bf841886da0b97 \
1303     --hash=sha256:a0c39e2535a7e9c195af956610dba5a1073071d2d85e9d2e5d789463f63e52ab \
1304     --hash=sha256:a15e75d284178afe529a536b0e8b28b7e107ef39626a7809b4ee64ff3abc9127 \
1305     --hash=sha256:a6a6ff82f5f9b9702478035d8f6fb6903885653bff7ec3a1e011edc9b1a7168d \
1306     --hash=sha256:b639f72b95389620c1f881d94739c614d385406ab1d6926a9ffe1c8abbea23fe \
1307     --hash=sha256:bad44274b151d46619a7567010f7cde23a908c6faa84b97598fd2f474a0c6891 \
1308     --hash=sha256:bbcef00d09a30948756c5968863316c949d9cedbc7aabac5e8f0ffbdb632e5f1 \
1309     --hash=sha256:d788a3999014ddf416f2dc454efa4a5dbeda657c6aba031cf363741273804c6b \
1310     --hash=sha256:eed88ae03e1ef3a75a0e96a55a99d7937ed03e53d0cffc2451c208db445a2966 \
1311     --hash=sha256:f99451f3a579e73b5dd58b1b08d1179791d49084371d9a47baad3b22417f0317
1312 zope.proxy==4.3.1 \
1313     --hash=sha256:0cbcfcafaa3b5fde7ba7a7b9a2b5f09af25c9b90087ad65f9e61359fed0ca63b \
1314     --hash=sha256:3de631dd5054a3a20b9ebff0e375f39c0565f1fb9131200d589a6a8f379214cd \
1315     --hash=sha256:5429134d04d42262f4dac25f6dea907f6334e9a751ffc62cb1d40226fb52bdeb \
1316     --hash=sha256:563c2454b2d0f23bca54d2e0e4d781149b7b06cb5df67e253ca3620f37202dd2 \
1317     --hash=sha256:5bcf773345016b1461bb07f70c635b9386e5eaaa08e37d3939dcdf12d3fdbec5 \
1318     --hash=sha256:8d84b7aef38c693874e2f2084514522bf73fd720fde0ce2a9352a51315ffa475 \
1319     --hash=sha256:90de9473c05819b36816b6cb957097f809691836ed3142648bf62da84b4502fe \
1320     --hash=sha256:dd592a69fe872445542a6e1acbefb8e28cbe6b4007b8f5146da917e49b155cc3 \
1321     --hash=sha256:e7399ab865399fce322f9cefc6f2f3e4099d087ba581888a9fea1bbe1db42a08 \
1322     --hash=sha256:e7d1c280d86d72735a420610df592aac72332194e531a8beff43a592c3a1b8eb \
1323     --hash=sha256:e90243fee902adb0c39eceb3c69995c0f2004bc3fdb482fbf629efc656d124ed
1324
1325 # Contains the requirements for the letsencrypt package.
1326 #
1327 # Since the letsencrypt package depends on certbot and using pip with hashes
1328 # requires that all installed packages have hashes listed, this allows
1329 # dependency-requirements.txt to be used without requiring a hash for a
1330 # (potentially unreleased) Certbot package.
1331
1332 letsencrypt==0.7.0 \
1333     --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
1334     --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
1335
1336 certbot==0.37.2 \
1337     --hash=sha256:8f6f0097fb2aac64f13e5d6974781ac85a051d84a6cb3f4d79c6b75c5ea451b8 \
1338     --hash=sha256:e454368aa8d62559c673091b511319c130c8e0ea1c4dfa314ed7bdc91dd96ef5
1339 acme==0.37.2 \
1340     --hash=sha256:5666ba927a9e7bf3f9ed5a268bd5acf627b5838fb409e8401f05d2aaaee188ba \
1341     --hash=sha256:88798fae3bc692397db79c66930bd02fcaba8a6b1fba9a62f111dda42cc47f5c
1342 certbot-apache==0.37.2 \
1343     --hash=sha256:e3ae7057f727506ab3796095ed66ca083f4e295d06f209ab96d2a3f37dea51b9 \
1344     --hash=sha256:4cb44d1a7c56176a84446a11412c561479ed0fed19848632e61f104dbf6a3031
1345 certbot-nginx==0.37.2 \
1346     --hash=sha256:a92dffdf3daca97db5d7ae2287e505110c3fa01c035b9356abb2ef9fa32e8695 \
1347     --hash=sha256:404f7b5b7611f0dce8773739170f306e94a59b69528cb74337e7f354936ac061
1348
1349 UNLIKELY_EOF
1350     # -------------------------------------------------------------------------
1351     cat << "UNLIKELY_EOF" > "$TEMP_DIR/pipstrap.py"
1352 #!/usr/bin/env python
1353 """A small script that can act as a trust root for installing pip >=8
1354 Embed this in your project, and your VCS checkout is all you have to trust. In
1355 a post-peep era, this lets you claw your way to a hash-checking version of pip,
1356 with which you can install the rest of your dependencies safely. All it assumes
1357 is Python 2.6 or better and *some* version of pip already installed. If
1358 anything goes wrong, it will exit with a non-zero status code.
1359 """
1360 # This is here so embedded copies are MIT-compliant:
1361 # Copyright (c) 2016 Erik Rose
1362 #
1363 # Permission is hereby granted, free of charge, to any person obtaining a copy
1364 # of this software and associated documentation files (the "Software"), to
1365 # deal in the Software without restriction, including without limitation the
1366 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
1367 # sell copies of the Software, and to permit persons to whom the Software is
1368 # furnished to do so, subject to the following conditions:
1369 #
1370 # The above copyright notice and this permission notice shall be included in
1371 # all copies or substantial portions of the Software.
1372 from __future__ import print_function
1373 from distutils.version import StrictVersion
1374 from hashlib import sha256
1375 from os import environ
1376 from os.path import join
1377 from shutil import rmtree
1378 try:
1379     from subprocess import check_output
1380 except ImportError:
1381     from subprocess import CalledProcessError, PIPE, Popen
1382
1383     def check_output(*popenargs, **kwargs):
1384         if 'stdout' in kwargs:
1385             raise ValueError('stdout argument not allowed, it will be '
1386                              'overridden.')
1387         process = Popen(stdout=PIPE, *popenargs, **kwargs)
1388         output, unused_err = process.communicate()
1389         retcode = process.poll()
1390         if retcode:
1391             cmd = kwargs.get("args")
1392             if cmd is None:
1393                 cmd = popenargs[0]
1394             raise CalledProcessError(retcode, cmd)
1395         return output
1396 import sys
1397 from tempfile import mkdtemp
1398 try:
1399     from urllib2 import build_opener, HTTPHandler, HTTPSHandler
1400 except ImportError:
1401     from urllib.request import build_opener, HTTPHandler, HTTPSHandler
1402 try:
1403     from urlparse import urlparse
1404 except ImportError:
1405     from urllib.parse import urlparse  # 3.4
1406
1407
1408 __version__ = 1, 5, 1
1409 PIP_VERSION = '9.0.1'
1410 DEFAULT_INDEX_BASE = 'https://pypi.python.org'
1411
1412
1413 # wheel has a conditional dependency on argparse:
1414 maybe_argparse = (
1415     [('18/dd/e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/'
1416       'argparse-1.4.0.tar.gz',
1417       '62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')]
1418     if sys.version_info < (2, 7, 0) else [])
1419
1420
1421 PACKAGES = maybe_argparse + [
1422     # Pip has no dependencies, as it vendors everything:
1423     ('11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/'
1424      'pip-{0}.tar.gz'.format(PIP_VERSION),
1425      '09f243e1a7b461f654c26a725fa373211bb7ff17a9300058b205c61658ca940d'),
1426     # This version of setuptools has only optional dependencies:
1427     ('37/1b/b25507861991beeade31473868463dad0e58b1978c209de27384ae541b0b/'
1428      'setuptools-40.6.3.zip',
1429      '3b474dad69c49f0d2d86696b68105f3a6f195f7ab655af12ef9a9c326d2b08f8'),
1430     ('c9/1d/bd19e691fd4cfe908c76c429fe6e4436c9e83583c4414b54f6c85471954a/'
1431      'wheel-0.29.0.tar.gz',
1432      '1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648')
1433 ]
1434
1435
1436 class HashError(Exception):
1437     def __str__(self):
1438         url, path, actual, expected = self.args
1439         return ('{url} did not match the expected hash {expected}. Instead, '
1440                 'it was {actual}. The file (left at {path}) may have been '
1441                 'tampered with.'.format(**locals()))
1442
1443
1444 def hashed_download(url, temp, digest):
1445     """Download ``url`` to ``temp``, make sure it has the SHA-256 ``digest``,
1446     and return its path."""
1447     # Based on pip 1.4.1's URLOpener but with cert verification removed. Python
1448     # >=2.7.9 verifies HTTPS certs itself, and, in any case, the cert
1449     # authenticity has only privacy (not arbitrary code execution)
1450     # implications, since we're checking hashes.
1451     def opener(using_https=True):
1452         opener = build_opener(HTTPSHandler())
1453         if using_https:
1454             # Strip out HTTPHandler to prevent MITM spoof:
1455             for handler in opener.handlers:
1456                 if isinstance(handler, HTTPHandler):
1457                     opener.handlers.remove(handler)
1458         return opener
1459
1460     def read_chunks(response, chunk_size):
1461         while True:
1462             chunk = response.read(chunk_size)
1463             if not chunk:
1464                 break
1465             yield chunk
1466
1467     parsed_url = urlparse(url)
1468     response = opener(using_https=parsed_url.scheme == 'https').open(url)
1469     path = join(temp, parsed_url.path.split('/')[-1])
1470     actual_hash = sha256()
1471     with open(path, 'wb') as file:
1472         for chunk in read_chunks(response, 4096):
1473             file.write(chunk)
1474             actual_hash.update(chunk)
1475
1476     actual_digest = actual_hash.hexdigest()
1477     if actual_digest != digest:
1478         raise HashError(url, path, actual_digest, digest)
1479     return path
1480
1481
1482 def get_index_base():
1483     """Return the URL to the dir containing the "packages" folder.
1484     Try to wring something out of PIP_INDEX_URL, if set. Hack "/simple" off the
1485     end if it's there; that is likely to give us the right dir.
1486     """
1487     env_var = environ.get('PIP_INDEX_URL', '').rstrip('/')
1488     if env_var:
1489         SIMPLE = '/simple'
1490         if env_var.endswith(SIMPLE):
1491             return env_var[:-len(SIMPLE)]
1492         else:
1493             return env_var
1494     else:
1495         return DEFAULT_INDEX_BASE
1496
1497
1498 def main():
1499     python = sys.executable or 'python'
1500     pip_version = StrictVersion(check_output([python, '-m', 'pip', '--version'])
1501                                 .decode('utf-8').split()[1])
1502     has_pip_cache = pip_version >= StrictVersion('6.0')
1503     index_base = get_index_base()
1504     temp = mkdtemp(prefix='pipstrap-')
1505     try:
1506         downloads = [hashed_download(index_base + '/packages/' + path,
1507                                      temp,
1508                                      digest)
1509                      for path, digest in PACKAGES]
1510         # Calling pip as a module is the preferred way to avoid problems about pip self-upgrade.
1511         command = [python, '-m', 'pip', 'install', '--no-index', '--no-deps', '-U']
1512         # Disable cache since it is not used and it otherwise sometimes throws permission warnings:
1513         command.extend(['--no-cache-dir'] if has_pip_cache else [])
1514         command.extend(downloads)
1515         check_output(command)
1516     except HashError as exc:
1517         print(exc)
1518     except Exception:
1519         rmtree(temp)
1520         raise
1521     else:
1522         rmtree(temp)
1523         return 0
1524     return 1
1525
1526
1527 if __name__ == '__main__':
1528     sys.exit(main())
1529
1530 UNLIKELY_EOF
1531     # -------------------------------------------------------------------------
1532     # Set PATH so pipstrap upgrades the right (v)env:
1533     PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py"
1534     set +e
1535     if [ "$VERBOSE" = 1 ]; then
1536       "$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt"
1537     else
1538       PIP_OUT=`"$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&1`
1539     fi
1540     PIP_STATUS=$?
1541     set -e
1542     if [ "$PIP_STATUS" != 0 ]; then
1543       # Report error. (Otherwise, be quiet.)
1544       error "Had a problem while installing Python packages."
1545       if [ "$VERBOSE" != 1 ]; then
1546         error
1547         error "pip prints the following errors: "
1548         error "====================================================="
1549         error "$PIP_OUT"
1550         error "====================================================="
1551         error
1552         error "Certbot has problem setting up the virtual environment."
1553
1554         if `echo $PIP_OUT | grep -q Killed` || `echo $PIP_OUT | grep -q "allocate memory"` ; then
1555           error
1556           error "Based on your pip output, the problem can likely be fixed by "
1557           error "increasing the available memory."
1558         else
1559           error
1560           error "We were not be able to guess the right solution from your pip "
1561           error "output."
1562         fi
1563
1564         error
1565         error "Consult https://certbot.eff.org/docs/install.html#problems-with-python-virtual-environment"
1566         error "for possible solutions."
1567         error "You may also find some support resources at https://certbot.eff.org/support/ ."
1568       fi
1569       rm -rf "$VENV_PATH"
1570       exit 1
1571     fi
1572
1573     if [ -d "$OLD_VENV_PATH" -a ! -L "$OLD_VENV_PATH" ]; then
1574       rm -rf "$OLD_VENV_PATH"
1575       ln -s "$VENV_PATH" "$OLD_VENV_PATH"
1576     fi
1577
1578     say "Installation succeeded."
1579   fi
1580
1581   if [ "$INSTALL_ONLY" = 1 ]; then
1582     say "Certbot is installed."
1583     exit 0
1584   fi
1585
1586   "$VENV_BIN/letsencrypt" "$@"
1587
1588 else
1589   # Phase 1: Upgrade certbot-auto if necessary, then self-invoke.
1590   #
1591   # Each phase checks the version of only the thing it is responsible for
1592   # upgrading. Phase 1 checks the version of the latest release of
1593   # certbot-auto (which is always the same as that of the certbot
1594   # package). Phase 2 checks the version of the locally installed certbot.
1595   export PHASE_1_VERSION="$LE_AUTO_VERSION"
1596
1597   if [ ! -f "$VENV_BIN/letsencrypt" ]; then
1598     if ! OldVenvExists; then
1599       if [ "$HELP" = 1 ]; then
1600         echo "$USAGE"
1601         exit 0
1602       fi
1603       # If it looks like we've never bootstrapped before, bootstrap:
1604       Bootstrap
1605     fi
1606   fi
1607   if [ "$OS_PACKAGES_ONLY" = 1 ]; then
1608     say "OS packages installed."
1609     exit 0
1610   fi
1611
1612   DeterminePythonVersion "NOCRASH"
1613   # Don't warn about file permissions if the user disabled the check or we
1614   # can't find an up-to-date Python.
1615   if [ "$PYVER" -ge "$MIN_PYVER" -a "$NO_PERMISSIONS_CHECK" != 1 ]; then
1616     # If the script fails for some reason, don't break certbot-auto.
1617     set +e
1618     # Suppress unexpected error output.
1619     CHECK_PERM_OUT=$(CheckPathPermissions "$LE_PYTHON" "$0" 2>/dev/null)
1620     CHECK_PERM_STATUS="$?"
1621     set -e
1622     # Only print output if the script ran successfully and it actually produced
1623     # output. The latter check resolves
1624     # https://github.com/certbot/certbot/issues/7012.
1625     if [ "$CHECK_PERM_STATUS" = 0 -a -n "$CHECK_PERM_OUT" ]; then
1626       error "$CHECK_PERM_OUT"
1627     fi
1628   fi
1629
1630   if [ "$NO_SELF_UPGRADE" != 1 ]; then
1631     TEMP_DIR=$(TempDir)
1632     trap 'rm -rf "$TEMP_DIR"' EXIT
1633     # ---------------------------------------------------------------------------
1634     cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py"
1635 """Do downloading and JSON parsing without additional dependencies. ::
1636
1637     # Print latest released version of LE to stdout:
1638     python fetch.py --latest-version
1639
1640     # Download letsencrypt-auto script from git tag v1.2.3 into the folder I'm
1641     # in, and make sure its signature verifies:
1642     python fetch.py --le-auto-script v1.2.3
1643
1644 On failure, return non-zero.
1645
1646 """
1647
1648 from __future__ import print_function, unicode_literals
1649
1650 from distutils.version import LooseVersion
1651 from json import loads
1652 from os import devnull, environ
1653 from os.path import dirname, join
1654 import re
1655 import ssl
1656 from subprocess import check_call, CalledProcessError
1657 from sys import argv, exit
1658 try:
1659     from urllib2 import build_opener, HTTPHandler, HTTPSHandler
1660     from urllib2 import HTTPError, URLError
1661 except ImportError:
1662     from urllib.request import build_opener, HTTPHandler, HTTPSHandler
1663     from urllib.error import HTTPError, URLError
1664
1665 PUBLIC_KEY = environ.get('LE_AUTO_PUBLIC_KEY', """-----BEGIN PUBLIC KEY-----
1666 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6MR8W/galdxnpGqBsYbq
1667 OzQb2eyW15YFjDDEMI0ZOzt8f504obNs920lDnpPD2/KqgsfjOgw2K7xWDJIj/18
1668 xUvWPk3LDkrnokNiRkA3KOx3W6fHycKL+zID7zy+xZYBuh2fLyQtWV1VGQ45iNRp
1669 9+Zo7rH86cdfgkdnWTlNSHyTLW9NbXvyv/E12bppPcEvgCTAQXgnDVJ0/sqmeiij
1670 n9tTFh03aM+R2V/21h8aTraAS24qiPCz6gkmYGC8yr6mglcnNoYbsLNYZ69zF1XH
1671 cXPduCPdPdfLlzVlKK1/U7hkA28eG3BIAMh6uJYBRJTpiGgaGdPd7YekUB8S6cy+
1672 CQIDAQAB
1673 -----END PUBLIC KEY-----
1674 """)
1675
1676 class ExpectedError(Exception):
1677     """A novice-readable exception that also carries the original exception for
1678     debugging"""
1679
1680
1681 class HttpsGetter(object):
1682     def __init__(self):
1683         """Build an HTTPS opener."""
1684         # Based on pip 1.4.1's URLOpener
1685         # This verifies certs on only Python >=2.7.9, and when NO_CERT_VERIFY isn't set.
1686         if environ.get('NO_CERT_VERIFY') == '1' and hasattr(ssl, 'SSLContext'):
1687             self._opener = build_opener(HTTPSHandler(context=cert_none_context()))
1688         else:
1689             self._opener = build_opener(HTTPSHandler())
1690         # Strip out HTTPHandler to prevent MITM spoof:
1691         for handler in self._opener.handlers:
1692             if isinstance(handler, HTTPHandler):
1693                 self._opener.handlers.remove(handler)
1694
1695     def get(self, url):
1696         """Return the document contents pointed to by an HTTPS URL.
1697
1698         If something goes wrong (404, timeout, etc.), raise ExpectedError.
1699
1700         """
1701         try:
1702             # socket module docs say default timeout is None: that is, no
1703             # timeout
1704             return self._opener.open(url, timeout=30).read()
1705         except (HTTPError, IOError) as exc:
1706             raise ExpectedError("Couldn't download %s." % url, exc)
1707
1708
1709 def write(contents, dir, filename):
1710     """Write something to a file in a certain directory."""
1711     with open(join(dir, filename), 'wb') as file:
1712         file.write(contents)
1713
1714
1715 def latest_stable_version(get):
1716     """Return the latest stable release of letsencrypt."""
1717     metadata = loads(get(
1718         environ.get('LE_AUTO_JSON_URL',
1719                     'https://pypi.python.org/pypi/certbot/json')).decode('UTF-8'))
1720     # metadata['info']['version'] actually returns the latest of any kind of
1721     # release release, contrary to https://wiki.python.org/moin/PyPIJSON.
1722     # The regex is a sufficient regex for picking out prereleases for most
1723     # packages, LE included.
1724     return str(max(LooseVersion(r) for r
1725                    in metadata['releases'].keys()
1726                    if re.match('^[0-9.]+$', r)))
1727
1728
1729 def verified_new_le_auto(get, tag, temp_dir):
1730     """Return the path to a verified, up-to-date letsencrypt-auto script.
1731
1732     If the download's signature does not verify or something else goes wrong
1733     with the verification process, raise ExpectedError.
1734
1735     """
1736     le_auto_dir = environ.get(
1737         'LE_AUTO_DIR_TEMPLATE',
1738         'https://raw.githubusercontent.com/certbot/certbot/%s/'
1739         'letsencrypt-auto-source/') % tag
1740     write(get(le_auto_dir + 'letsencrypt-auto'), temp_dir, 'letsencrypt-auto')
1741     write(get(le_auto_dir + 'letsencrypt-auto.sig'), temp_dir, 'letsencrypt-auto.sig')
1742     write(PUBLIC_KEY.encode('UTF-8'), temp_dir, 'public_key.pem')
1743     try:
1744         with open(devnull, 'w') as dev_null:
1745             check_call(['openssl', 'dgst', '-sha256', '-verify',
1746                         join(temp_dir, 'public_key.pem'),
1747                         '-signature',
1748                         join(temp_dir, 'letsencrypt-auto.sig'),
1749                         join(temp_dir, 'letsencrypt-auto')],
1750                        stdout=dev_null,
1751                        stderr=dev_null)
1752     except CalledProcessError as exc:
1753         raise ExpectedError("Couldn't verify signature of downloaded "
1754                             "certbot-auto.", exc)
1755
1756
1757 def cert_none_context():
1758     """Create a SSLContext object to not check hostname."""
1759     # PROTOCOL_TLS isn't available before 2.7.13 but this code is for 2.7.9+, so use this.
1760     context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
1761     context.verify_mode = ssl.CERT_NONE
1762     return context
1763
1764
1765 def main():
1766     get = HttpsGetter().get
1767     flag = argv[1]
1768     try:
1769         if flag == '--latest-version':
1770             print(latest_stable_version(get))
1771         elif flag == '--le-auto-script':
1772             tag = argv[2]
1773             verified_new_le_auto(get, tag, dirname(argv[0]))
1774     except ExpectedError as exc:
1775         print(exc.args[0], exc.args[1])
1776         return 1
1777     else:
1778         return 0
1779
1780
1781 if __name__ == '__main__':
1782     exit(main())
1783
1784 UNLIKELY_EOF
1785     # ---------------------------------------------------------------------------
1786     if [ "$PYVER" -lt "$MIN_PYVER" ]; then
1787       error "WARNING: couldn't find Python $MIN_PYTHON_VERSION+ to check for updates."
1788     elif ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
1789       error "WARNING: unable to check for updates."
1790     fi
1791
1792     LE_VERSION_STATE=`CompareVersions "$LE_PYTHON" "$LE_AUTO_VERSION" "$REMOTE_VERSION"`
1793     if [ "$LE_VERSION_STATE" = "UNOFFICIAL" ]; then
1794       say "Unofficial certbot-auto version detected, self-upgrade is disabled: $LE_AUTO_VERSION"
1795     elif [ "$LE_VERSION_STATE" = "OUTDATED" ]; then
1796       say "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
1797
1798       # Now we drop into Python so we don't have to install even more
1799       # dependencies (curl, etc.), for better flow control, and for the option of
1800       # future Windows compatibility.
1801       "$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION"
1802
1803       # Install new copy of certbot-auto.
1804       # TODO: Deal with quotes in pathnames.
1805       say "Replacing certbot-auto..."
1806       # Clone permissions with cp. chmod and chown don't have a --reference
1807       # option on macOS or BSD, and stat -c on Linux is stat -f on macOS and BSD:
1808       cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
1809       cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
1810       # Using mv rather than cp leaves the old file descriptor pointing to the
1811       # original copy so the shell can continue to read it unmolested. mv across
1812       # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the
1813       # cp is unlikely to fail if the rm doesn't.
1814       mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
1815     fi  # A newer version is available.
1816   fi  # Self-upgrading is allowed.
1817
1818   RerunWithArgs --le-auto-phase2 "$@"
1819 fi