268
268
# 2021-07-27 Support ftps://, FTPS_OPTIONS, remove default --insecure parameter to ftpes. Report caller(s) of error_exit in debug and test modes (tlhackque)(#687)(2.39)
269
269
# 2021-07-30 Prefer API V2 when both offered (tlhackque) (#690) (2.40)
270
270
# 2021-07-30 Run tests with -d to catch intermittent failures, Use fork's repo for upgrade tests. (tlhackque) (#692) (2.41)
271
+ # 2021-08-26 Improve upgrade check & make upgrade do a full install when possible (tlhackque) (#694) (2.42)
271
272
# ----------------------------------------------------------------------------------------
272
273
273
274
case :$SHELLOPTS : in
276
277
277
278
PROGNAME=${0##*/ }
278
279
PROGDIR=" $( cd " $( dirname " $0 " ) " || exit ; pwd -P; ) "
279
- VERSION=" 2.41 "
280
+ VERSION=" 2.42 "
280
281
281
282
# defaults
282
283
ACCOUNT_KEY_LENGTH=4096
@@ -286,10 +287,11 @@ CA="https://acme-staging-v02.api.letsencrypt.org/directory"
286
287
CHALLENGE_CHECK_TYPE=" http"
287
288
CHECK_REMOTE_WAIT=0
288
289
CHECK_REMOTE=" true"
290
+ LIMIT_API=" https://api.github.com/rate_limit"
289
291
if [[ -n " ${GITHUB_REPOSITORY} " ]] ; then
290
- CODE_LOCATION =" https://raw.githubusercontent .com/${GITHUB_REPOSITORY} /master/getssl "
292
+ RELEASE_API =" https://api.github .com/repos/ ${GITHUB_REPOSITORY} /releases/latest "
291
293
else
292
- CODE_LOCATION =" https://raw.githubusercontent .com/srvrco/getssl/master/getssl "
294
+ RELEASE_API =" https://api.github .com/repos/ srvrco/getssl/releases/latest "
293
295
fi
294
296
CSR_SUBJECT=" /"
295
297
CURL_USERAGENT=" ${PROGNAME} /${VERSION} "
@@ -314,7 +316,7 @@ REUSE_PRIVATE_KEY="true"
314
316
SERVER_TYPE=" https"
315
317
SKIP_HTTP_TOKEN_CHECK=" false"
316
318
SSLCONF=" $( openssl version -d 2> /dev/null| cut -d\" -f2) /openssl.cnf"
317
- TEMP_UPGRADE_FILE =" "
319
+ TEMP_UPGRADE_DIR =" "
318
320
TOKEN_USER_ID=" "
319
321
USE_SINGLE_ACL=" false"
320
322
WORKING_DIR_CANDIDATES=(" /etc/getssl" " ${PROGDIR} /conf" " ${PROGDIR} /.getssl" " ${HOME} /.getssl" )
@@ -338,7 +340,6 @@ _CHECK_ALL=0
338
340
_CREATE_CONFIG=0
339
341
_CURL_VERSION=" "
340
342
_FORCE_RENEW=0
341
- _KEEP_VERSIONS=" "
342
343
_MUTE=0
343
344
_NOTIFY_VALID=0
344
345
_NOMETER=" "
@@ -351,6 +352,7 @@ _TEST_SKIP_CNAME_CALL=0
351
352
_TEST_SKIP_SOA_CALL=0
352
353
_UPGRADE=0
353
354
_UPGRADE_CHECK=1
355
+ _UPGRADE_TO_TAG=" "
354
356
_USE_DEBUG=0
355
357
_ONLY_CHECK_CONFIG=0
356
358
config_errors=" false"
@@ -761,71 +763,165 @@ check_config() { # check the config files for all obvious errors
761
763
debug " ${DOMAIN} : check_config completed - all OK"
762
764
}
763
765
764
- check_getssl_upgrade () { # check if a more recent version of code is available available
765
- TEMP_UPGRADE_FILE=" $( mktemp 2> /dev/null || mktemp -t getssl.XXXXXX) "
766
- if [ " $TEMP_UPGRADE_FILE " == " " ]; then
767
- error_exit " mktemp failed"
768
- fi
769
- curl ${_NOMETER} --user-agent " $CURL_USERAGENT " --silent " $CODE_LOCATION " --output " $TEMP_UPGRADE_FILE "
766
+ # Quota generally shouldn't be an issue - except for tests
767
+ # Rate limits are per-IP address
768
+ check_github_quota () {
769
+ local need remaining reset limits now
770
+ need=" $1 "
771
+ while true ; do
772
+ limits=" $( curl ${_NOMETER:- --silent} --user-agent " $CURL_USERAGENT " -H ' Accept: application/vnd.github.v3+json' " $LIMIT_API " | sed -e' s/\("[^:]*": *\("[^""]*",\|[^,]*[,}]\)\)/\r\n\1/g' | sed -ne' /"core":/,/}/p' ) "
773
+ errcode=$?
774
+ if [[ $errcode -eq 60 ]]; then
775
+ error_exit " curl needs updating, your version does not support SNI (multiple SSL domains on a single IP)"
776
+ elif [[ $errcode -gt 0 ]]; then
777
+ error_exit " curl error checking releases: $errcode "
778
+ fi
779
+ limits=" $( sed -e' s/^ *//g' <<< " ${limits}" ) "
780
+ remaining=" $( sed -e' /^"remaining": *[0-9]/!d;s/^"remaining": *\([0-9][0-9]*\).*$/\1/' <<< " ${limits}" ) "
781
+ reset=" $( sed -e' /^"reset": *[0-9]/!d;s/^"reset": *\([0-9][0-9]*\).*$/\1/' <<< " ${limits}" ) "
782
+ if [[ " $remaining " -ge " $need " ]] ; then return 0 ; fi
783
+ limit=" $( sed -e' /^"limit": *[0-9]/!d;s/^"limit": *\([0-9][0-9]*\).*$/\1/' <<< " ${limits}" ) "
784
+ if [[ " $limit " -lt " $need " ]] ; then
785
+ error_exit " GitHub API request $need exceeds limit $limit "
786
+ fi
787
+ now=" $( date +%s) "
788
+ while [[ " $now " -lt " $reset " ]] ; do
789
+ info " sleeping $(( "$reset " - "$now " )) seconds for GitHub quota"
790
+ sleep " $(( "$reset " - "$now " )) "
791
+ now=" $( date +%s) "
792
+ done
793
+ done
794
+ }
795
+ check_getssl_upgrade () { # check if a more recent release is available
796
+ check_github_quota 2
797
+ # Check GitHub for latest stable release, or a specified tag
798
+ if [[ -n " $_UPGRADE_TO_TAG " ]]; then
799
+ RELEASE_API=" $RELEASE_API /tags/$_UPGRADE_TO_TAG "
800
+ fi
801
+ local release_data release_tag release_ver local_ver release_desc release_url release_tar NEWCMD
802
+ debug " Checking for releases at $RELEASE_API "
803
+ # Sometimes the json is pretty-printed, sometimes not. Loosely tied to --user-agent, but not
804
+ # always. Normalize it enough to get the 3 elements necessary. Oh, for jq...
805
+ release_data=" $( curl ${_NOMETER:- --silent} --user-agent " $CURL_USERAGENT " -H ' Accept: application/vnd.github.v3+json' " $RELEASE_API " | sed -e' s/\("[^:]*": *\("[^""]*",\|[^,]*[,}]\)\)/\r\n\1/g' ) "
770
806
errcode=$?
771
807
if [[ $errcode -eq 60 ]]; then
772
808
error_exit " curl needs updating, your version does not support SNI (multiple SSL domains on a single IP)"
773
809
elif [[ $errcode -gt 0 ]]; then
774
- error_exit " curl error : $errcode "
810
+ error_exit " curl error checking releases: $errcode "
811
+ fi
812
+ debug " $release_data "
813
+ release_data=" $( sed -e' s/^ *//g' <<< " ${release_data}" ) "
814
+ release_tag=" $( sed -e' /^"tag_name": *"/!d;s/^"tag_name": *"\([^""]*\).*$/\1/' <<< " ${release_data}" ) "
815
+ if [[ " ${release_tag: 0: 1} " != ' v' ]] ; then
816
+ if [[ ${_MUTE} -eq 0 ]]; then
817
+ info " The current repository has no releases or is improperly tagged; can't check for upgrades: '$release_tag '"
818
+ fi
819
+ return 0
775
820
fi
776
- latestversion=$( awk -F ' "' ' $1 == "VERSION=" {print $2}' " $TEMP_UPGRADE_FILE " )
777
- latestvdec=$( echo " $latestversion " | tr -d ' .' )
778
- localvdec=$( echo " $VERSION " | tr -d ' .' )
821
+ release_ver=" $( tr -d ' .v' <<< " ${release_tag}" ) "
822
+ local_ver=" $( tr -d ' .' <<< " ${VERSION}" ) "
779
823
debug " current code is version ${VERSION} "
780
- debug " Most recent version is ${latestversion} "
781
- # use a default of 0 for cases where the latest code has not been obtained.
782
- if [[ " ${latestvdec:- 0} " -gt " $localvdec " ]]; then
783
- if [[ ${_UPGRADE} -eq 1 ]]; then
784
- if ! install " $0 " " ${0} .v${VERSION} " ; then
785
- error_exit " problem renaming old version while updating, check permissions"
786
- fi
787
- if ! install -m 700 " $TEMP_UPGRADE_FILE " " $0 " ; then
788
- error_exit " problem installing new version while updating, check permissions"
789
- fi
790
- if [[ ${_MUTE} -eq 0 ]]; then
791
- echo " Updated getssl from v${VERSION} to v${latestversion} "
792
- echo " These update notifications can be turned off using the -Q option"
793
- echo " "
794
- echo " Updates are;"
795
- awk " /\(${VERSION} \)$/ {s=1} s; /\(${latestversion} \)$/ || /^# ----/ {s=0}" " $TEMP_UPGRADE_FILE " | awk ' {if(NR>1)print}'
796
- echo " "
797
- fi
798
- if [[ -n " $_KEEP_VERSIONS " ]] && [[ " $_KEEP_VERSIONS " =~ ^[0-9]+$ ]]; then
799
- # Obtain all locally stored old versions in getssl_versions
800
- declare -a getssl_versions
801
- shopt -s nullglob
802
- for getssl_version in " $0 " .v* ; do
803
- getssl_versions[${# getssl_versions[@]} ]=" $getssl_version "
804
- done
805
- shopt -u nullglob
806
- # Explicitly sort the getssl_versions array to make sure
807
- shopt -s -o noglob
808
- # shellcheck disable=SC2207
809
- IFS=$' \n ' getssl_versions=($( sort <<< " ${getssl_versions[*]}" ) )
810
- shopt -u -o noglob
811
- # Remove entries until given number of old versions to keep is reached
812
- while [[ ${# getssl_versions[@]} -gt $_KEEP_VERSIONS ]]; do
813
- debug " removing old version ${getssl_versions[0]} "
814
- rm " ${getssl_versions[0]} "
815
- getssl_versions=(" ${getssl_versions[@]: 1} " )
816
- done
817
- fi
818
- if ! eval " $ORIGCMD " ; then
819
- error_exit " Running upgraded getssl failed"
820
- fi
821
- graceful_exit
822
- else
824
+ debug " Most recent version is ${release_tag: 1} "
825
+ if [[ -z " $_UPGRADE_TO_TAG " ]] ; then
826
+ if [[ " $local_ver " -ge " $release_ver " ]] ; then return 0; fi
827
+ else
828
+ if [[ " $local_ver " -eq " $release_ver " ]] ; then return 0; fi
829
+ fi
830
+ if [[ ${_UPGRADE} -ne 1 ]]; then
831
+ if [[ ${_MUTE} -eq 0 ]]; then
832
+ release_desc=" $( sed -e' /^"body": *"/!d;s/^"body": *"\([^""]*\).*$/\1/;s/\\r/\r/g;s/\\n/\n/g' <<< " $release_data" ) "
823
833
info " "
824
- info " A more recent version (v ${latestversion} ) of getssl is available, please update"
834
+ info " A more recent version (${release_tag} ) than $VERSION of getssl is available, please update"
825
835
info " The easiest way is to use the -u or --upgrade flag"
826
836
info " "
837
+ info " Release ${release_tag} summary"
838
+ info " $release_desc "
839
+ info " "
827
840
fi
841
+ return 0;
842
+ fi
843
+ # Find, download, and unpack the tarball containing the selected release
844
+ release_url=" $( sed -e' /^"tarball_url": *"/!d;s/^"tarball_url": *"\([^""]*\).*$/\1/' <<< " ${release_data}" ) "
845
+ debug " Release url '$release_url '"
846
+ requires tar
847
+ TEMP_UPGRADE_DIR=" $( mktemp -d 2> /dev/null || mktemp -d -t getssl.XXXXXXXX) "
848
+ if [ " $TEMP_UPGRADE_DIR " == " " ]; then
849
+ error_exit " mktemp failed"
850
+ fi
851
+ release_tar=" $TEMP_UPGRADE_DIR /getssl-${release_tag} .tgz"
852
+ debug " Downloading release to $release_tar "
853
+ check_github_quota 1
854
+ curl ${_NOMETER:- --silent} -L --user-agent " $CURL_USERAGENT " -H ' Accept: application/vnd.github.v3+json' " $release_url " --output " $release_tar "
855
+ errcode=$?
856
+ if [[ $errcode -eq 60 ]]; then
857
+ error_exit " curl needs updating, your version does not support SNI (multiple SSL domains on a single IP)"
858
+ elif [[ $errcode -gt 0 ]]; then
859
+ error_exit " curl error downloading release: $errcode "
860
+ fi
861
+ if ! tar -C " ${TEMP_UPGRADE_DIR} " --strip-components 1 -xzf " $release_tar " ; then
862
+ error_exit " failed to unpack release: $? "
828
863
fi
864
+ # Inhibit check for upgrades when running the new version
865
+ NEWCMD=" $( sed -e' s/ -\(u\|-upgrade\|U\|-nocheck\)//g;s/^\([^ ]* \)/\1--nocheck /' <<< " $ORIGCMD" ) "
866
+ # Install everything with make - if it's available
867
+ if [ -n " $( command -v ' make' 2> /dev/null) " ]; then
868
+ if [[ " ${0%/ usr/ bin/ getssl} " != " $0 " ]] ; then
869
+ export DESTDIR=" ${0%/ usr/ bin/ getssl} "
870
+ fi
871
+ if [[ ${_MUTE} -eq 0 ]]; then
872
+ if ! make -C " ${TEMP_UPGRADE_DIR} " " install" ; then
873
+ error_exit " Installation failed: $? "
874
+ fi
875
+ else
876
+ if ! make -s -C " ${TEMP_UPGRADE_DIR} " " install" > /dev/null ; then
877
+ error_exit " Installation failed: $? "
878
+ fi
879
+ fi
880
+ clean_up
881
+ if [[ ${_MUTE} -eq 0 ]]; then
882
+ info " Installed $release_tag , restarting with $NEWCMD "
883
+ fi
884
+ if ! eval " $NEWCMD " ; then
885
+ error_exit " Running upgraded getssl failed"
886
+ fi
887
+ graceful_exit
888
+ fi
889
+ # Fall back to 'install' and just the main script.
890
+ if [[ ${_MUTE} -eq 0 ]]; then
891
+ info " 'make' is not available. getssl will be installed, but support scripts will not be upgraded"
892
+ info " To stay completely up-to-date, please install make"
893
+ fi
894
+ if ! install " $0 " " ${0} .v${VERSION} " ; then
895
+ error_exit " problem renaming old version while updating, check permissions"
896
+ fi
897
+ if ! install -m 700 " $TEMP_UPGRADE_DIR /getssl" " $0 " ; then
898
+ error_exit " problem installing new version while updating, check permissions"
899
+ fi
900
+ if [[ ${_MUTE} -eq 0 ]]; then
901
+ echo " Updated getssl from v${VERSION} to $release_tag "
902
+ echo " The old version remains as ${0} .v${VERSION} and should be removed"
903
+ echo " "
904
+ fi
905
+ # This version can't be removed since disappearing can confuse bash.
906
+ declare -a getssl_versions
907
+ shopt -s nullglob
908
+ for getssl_version in " $0 " .v* ; do
909
+ if [[ " $getssl_version " != " ${0} .v${VERSION} " ]] ; then
910
+ getssl_versions[${# getssl_versions[@]} ]=" $getssl_version "
911
+ fi
912
+ done
913
+ shopt -u nullglob
914
+ if [[ -n " ${getssl_versions[*]} " ]] ; then
915
+ rm " ${getssl_versions[@]} "
916
+ fi
917
+ clean_up
918
+ if [[ ${_MUTE} -eq 0 ]]; then
919
+ info " Installed $release_tag , restarting with $NEWCMD "
920
+ fi
921
+ if ! eval " $NEWCMD " ; then
922
+ error_exit " Running upgraded getssl failed"
923
+ fi
924
+ graceful_exit
829
925
}
830
926
831
927
clean_up () { # Perform pre-exit housekeeping
@@ -848,8 +944,12 @@ clean_up() { # Perform pre-exit housekeeping
848
944
rm -rf " ${TEMP_DIR:? } "
849
945
fi
850
946
fi
851
- if [[ -n " $TEMP_UPGRADE_FILE " ]] && [[ -f " $TEMP_UPGRADE_FILE " ]]; then
852
- rm -f " $TEMP_UPGRADE_FILE "
947
+ if [[ -n " $TEMP_UPGRADE_DIR " ]] && [[ -d " $TEMP_UPGRADE_DIR " ]]; then
948
+ if [ " ${TEMP_UPGRADE_DIR} " -ef " /tmp" ]; then
949
+ info " Not going to delete TEMP_UPGRADE_DIR ${TEMP_UPGRADE_DIR} as it appears to be /tmp"
950
+ else
951
+ rm -rf " ${TEMP_UPGRADE_DIR:? } "
952
+ fi
853
953
fi
854
954
}
855
955
@@ -1829,7 +1929,7 @@ help_message() { # print out the help message
1829
1929
-Q, --mute Like -q, but also mute notification about successful upgrade
1830
1930
-r, --revoke "cert" "key" [CA_server] Revoke a certificate (the cert and key are required)
1831
1931
-u, --upgrade Upgrade getssl if a more recent version is available - can be used with or without domain(s)
1832
- -k , --keep "#" Maximum number of old getssl versions to keep when upgrading
1932
+ -X , --experimental tag Upgrade to experimental releases, specified by tag (e.g. v9.43)
1833
1933
-U, --nocheck Do not check if a more recent version is available
1834
1934
-v --version Display current version of $PROGNAME
1835
1935
-w working_dir "Working directory"
@@ -2451,7 +2551,7 @@ urlbase64_decode() {
2451
2551
2452
2552
usage () { # echos out the program usage
2453
2553
echo " Usage: $PROGNAME [-h|--help] [-d|--debug] [-c|--create] [-f|--force] [-a|--all] [-q|--quiet]" \
2454
- " [-Q|--mute] [-u|--upgrade] [-k |--keep # ] [-U|--nocheck] [-r|--revoke cert key] [-w working_dir]" \
2554
+ " [-Q|--mute] [-u|--upgrade] [-X |--experimental tag ] [-U|--nocheck] [-r|--revoke cert key] [-w working_dir]" \
2455
2555
" [--preferred-chain chain] domain"
2456
2556
}
2457
2557
@@ -2660,7 +2760,8 @@ while [[ -n ${1+defined} ]]; do
2660
2760
-a | --all)
2661
2761
_CHECK_ALL=1 ;;
2662
2762
-k | --keep)
2663
- shift ; _KEEP_VERSIONS=" $1 " ;;
2763
+ shift ;
2764
+ echo " --keep has no effect" ;;
2664
2765
-q | --quiet)
2665
2766
_QUIET=1 ;;
2666
2767
-Q | --mute)
@@ -2678,6 +2779,9 @@ while [[ -n ${1+defined} ]]; do
2678
2779
REVOKE_REASON=0 ;;
2679
2780
-u | --upgrade)
2680
2781
_UPGRADE=1 ;;
2782
+ -X | --experimental)
2783
+ _UPGRADE_TO_TAG=" $1 "
2784
+ shift ;;
2681
2785
-U | --nocheck)
2682
2786
_UPGRADE_CHECK=0 ;;
2683
2787
-i | --install)
@@ -2747,6 +2851,15 @@ if [[ ! "${_CURL_VERSION}" < "7.67" ]]; then
2747
2851
_NOMETER=" --no-progress-meter"
2748
2852
fi
2749
2853
2854
+ # Make sure mktemp works before going too far
2855
+ MKDIR_TEST_FILE= " $( mktemp 2> /dev/null || mktemp -t getssl.XXXXXX) "
2856
+ if [ " $MKDIR_TEST_FILE " == " " ]; then
2857
+ error_exit " mktemp failed"
2858
+ else
2859
+ rm " $MKDIR_TEST_FILE "
2860
+ fi
2861
+ unset MKDIR_TEST_FILE
2862
+
2750
2863
# Check if upgrades are available (unless they have specified -U to ignore Upgrade checks)
2751
2864
if [[ $_UPGRADE_CHECK -eq 1 ]]; then
2752
2865
check_getssl_upgrade
0 commit comments