1111# #
1212set -u
1313
14- # Functions useful for dealing with the manifest (which is JSON).
15-
16- # Get the version of a tag from the manifest JSON file.
17- # Arguments:
18- # $1 - The tag to get.
19- # STDIN - The manifest file.
20- # Returns:
21- # 0 if the tag was found, 1 if it wasn't.
22- # Prints out the version number.
23- get_tag_from_manifest_json () {
24- # Find the tag in the file. Then get the last digits.
25- # The first grep returns `"tag_name": "1.2.3` (without the last quote).
26- cat \
27- | tr -d ' \n' \
28- | grep -o " \" $1 \" :[[:space:]]*\" [a-zA-Z0-9.]*" \
29- | grep -o " [0-9.]*$"
30- }
31-
3214# A newline separated list of boolean flags. See the read_flags function to see how it's parsed.
3315DFX_BOOL_FLAGS=" "
3416
@@ -111,7 +93,6 @@ err() {
11193 say " $1 " >&2
11294 exit 1
11395}
114- # # 110_assert.sh
11596
11697need_cmd () {
11798 if ! check_cmd " $1 " ; then
@@ -144,61 +125,81 @@ ignore() {
144125define_flag_BOOL " insecure" " Allows downloading from insecure URLs, either using HTTP or TLS 1.2 or less."
145126
146127check_help_for () {
128+ local _arch
147129 local _cmd
148130 local _arg
149- local _ok
131+ _arch=" $1 "
132+ shift
150133 _cmd=" $1 "
151- _ok=" y"
152134 shift
153135
154- # If we're running on OS-X, older than 10.13, then we always
155- # fail to find these options to force fallback
156- if check_cmd sw_vers; then
157- case " $( sw_vers -productVersion) " in
158- 10.15* ) ;; # Catalina
159- 11.* ) ;; # Big Sur
160- 12.* ) ;; # Monterey
161- 13.* ) ;; # Ventura
162- * )
163- warn " Detected OS X platform older than 10.15 (Catalina)"
164- _ok=" n"
165- ;;
166- esac
136+ local _category
137+ if " $_cmd " --help | grep -q ' For all options use the manual or "--help all".' ; then
138+ _category=" all"
139+ else
140+ _category=" "
167141 fi
168142
143+ case " $_arch " in
144+
145+ * darwin* )
146+ if check_cmd sw_vers; then
147+ case $( sw_vers -productVersion) in
148+ 10.* )
149+ # If we're running on macOS, older than 10.13, then we always
150+ # fail to find these options to force fallback
151+ if [ " $( sw_vers -productVersion | cut -d. -f2) " -lt 13 ]; then
152+ # Older than 10.13
153+ echo " Warning: Detected macOS platform older than 10.13"
154+ return 1
155+ fi
156+ ;;
157+
158+ # We assume these will be OK for now
159+ 11.* ) ;; # Big Sur
160+ 12.* ) ;; # Monterey
161+ 13.* ) ;; # Ventura
162+ 14.* ) ;; # Sonoma
163+
164+ * )
165+ # Unknown product version, warn and continue
166+ echo " Warning: Detected unknown macOS major version: $( sw_vers -productVersion) "
167+ echo " Warning TLS capabilities detection may fail"
168+ ;;
169+ esac
170+ fi
171+ ;;
172+
173+ esac
174+
169175 for _arg in " $@ " ; do
170- if ! " $_cmd " --help all | grep -q -- " $_arg " ; then
171- _ok= " n "
176+ if ! " $_cmd " --help " $_category " | grep -q -- " $_arg " ; then
177+ return 1
172178 fi
173179 done
174180
175- test " $_ok " = " y "
181+ true # not strictly needed
176182}
177183
178- # Check for an error message in the output of a command.
179- # Arguments:
180- # $1 - The error message to look for.
181- # $2... - The command and arguments to run.
182- # Returns:
183- # Whether false if the error message was not found, or true if it wasn't (so the feature is
184- # supported.
185- # TODO: move this logic to execute once during install.sh run.
186- check_support_for () {
187- local err=" $1 "
188- shift
189- local cmd=" $* "
190-
191- # Run the command, grep for the error message, if it is found returns false, if it
192- # is not found, returns true.
193- ! ($cmd 2>&1 | grep " $err " > /dev/null)
184+ is_zsh () {
185+ [ -n " ${ZSH_VERSION-} " ]
194186}
195187
196- # This wraps curl or wget. Try curl first, if not installed, use wget instead.
188+ # This wraps curl or wget. Try curl first, if not installed,
189+ # use wget instead.
197190# Arguments:
198191# $1 - URL to download.
199192# $2 - Path to output the download. Use - to output to stdout.
193+ # $3 - The architecture, used to determine TLS capabilities.
200194downloader () {
195+ # zsh does not split words by default, Required for curl retry arguments below.
196+ is_zsh && setopt local_options shwordsplit
197+
201198 local _dld
199+ local _ciphersuites
200+ local _err
201+ local _status
202+ local _retry
202203 if check_cmd curl; then
203204 _dld=curl
204205 elif check_cmd wget; then
@@ -210,28 +211,171 @@ downloader() {
210211 if [ " $1 " = --check ]; then
211212 need_cmd " $_dld "
212213 elif [ " $_dld " = curl ]; then
213- if check_help_for curl --proto --tlsv1.2; then
214- curl --proto ' =https' --tlsv1.2 --show-error --fail --connect-timeout 10 --retry 5 --location " $1 " --output " $2 " --progress-bar
215- elif ! [ " $flag_INSECURE " ]; then
216- warn " Not forcing TLS v1.2, this is potentially less secure"
217- curl --show-error --fail --connect-timeout 10 --retry 5 --location " $1 " --output " $2 " --progress-bar
214+ check_curl_for_retry_support
215+ _retry=" $RETVAL "
216+ get_ciphersuites_for_curl
217+ _ciphersuites=" $RETVAL "
218+ if [ -n " $_ciphersuites " ]; then
219+ # shellcheck disable=SC2086 # $retry is intentionally split
220+ _err=$( curl $_retry --proto ' =https' --tlsv1.2 --ciphers " $_ciphersuites " --silent --show-error --fail --location " $1 " --output " $2 " 2>&1 )
221+ _status=$?
218222 else
219- err " TLS 1.2 is not supported on this platform. To force using it, use the --insecure flag."
223+ echo " Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
224+ if ! check_help_for " $3 " curl --proto --tlsv1.2; then
225+ echo " Warning: Not enforcing TLS v1.2, this is potentially less secure"
226+ # shellcheck disable=SC2086 # $retry is intentionally split
227+ _err=$( curl $_retry --silent --show-error --fail --location " $1 " --output " $2 " 2>&1 )
228+ _status=$?
229+ else
230+ # shellcheck disable=SC2086 # $retry is intentionally split
231+ _err=$( curl $_retry --proto ' =https' --tlsv1.2 --silent --show-error --fail --location " $1 " --output " $2 " 2>&1 )
232+ _status=$?
233+ fi
220234 fi
235+ if [ -n " $_err " ]; then
236+ echo " $_err " >&2
237+ if echo " $_err " | grep -q 404$; then
238+ err " installer for platform '$3 ' not found, this may be unsupported"
239+ fi
240+ fi
241+ return $_status
221242 elif [ " $_dld " = wget ]; then
222- if check_help_for wget --https-only --secure-protocol; then
223- wget --https-only --secure-protocol=TLSv1_2 --timeout 10 --tries 5 --waitretry 5 " $1 " -O " $2 "
224- elif ! [ " $flag_INSECURE " ]; then
225- warn " Not forcing TLS v1.2, this is potentially less secure"
226- wget --timeout 10 --tries 5 --waitretry 5 " $1 " -O " $2 "
243+ if [ " $( wget -V 2>&1 | head -2 | tail -1 | cut -f1 -d" " ) " = " BusyBox" ]; then
244+ echo " Warning: using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure"
245+ _err=$( wget " $1 " -O " $2 " 2>&1 )
246+ _status=$?
227247 else
228- err " TLS 1.2 is not supported on this platform. To force using it, use the --insecure flag."
248+ get_ciphersuites_for_wget
249+ _ciphersuites=" $RETVAL "
250+ if [ -n " $_ciphersuites " ]; then
251+ _err=$( wget --https-only --secure-protocol=TLSv1_2 --ciphers " $_ciphersuites " " $1 " -O " $2 " 2>&1 )
252+ _status=$?
253+ else
254+ echo " Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
255+ if ! check_help_for " $3 " wget --https-only --secure-protocol; then
256+ echo " Warning: Not enforcing TLS v1.2, this is potentially less secure"
257+ _err=$( wget " $1 " -O " $2 " 2>&1 )
258+ _status=$?
259+ else
260+ _err=$( wget --https-only --secure-protocol=TLSv1_2 " $1 " -O " $2 " 2>&1 )
261+ _status=$?
262+ fi
263+ fi
229264 fi
265+ if [ -n " $_err " ]; then
266+ echo " $_err " >&2
267+ if echo " $_err " | grep -q ' 404 Not Found$' ; then
268+ err " installer for platform '$3 ' not found, this may be unsupported"
269+ fi
270+ fi
271+ return $_status
230272 else
231273 err " Unknown downloader" # should not reach here
232274 fi
233275}
234276
277+ # Check if curl supports the --retry flag, then pass it to the curl invocation.
278+ check_curl_for_retry_support () {
279+ local _retry_supported=" "
280+ # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
281+ if check_help_for " notspecified" " curl" " --retry" ; then
282+ _retry_supported=" --retry 3"
283+ if check_help_for " notspecified" " curl" " --continue-at" ; then
284+ # "-C -" tells curl to automatically find where to resume the download when retrying.
285+ _retry_supported=" --retry 3 -C -"
286+ fi
287+ fi
288+
289+ RETVAL=" $_retry_supported "
290+ }
291+
292+ # Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
293+ # if support by local tools is detected. Detection currently supports these curl backends:
294+ # GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
295+ get_ciphersuites_for_curl () {
296+ if [ -n " ${RUSTUP_TLS_CIPHERSUITES-} " ]; then
297+ # user specified custom cipher suites, assume they know what they're doing
298+ RETVAL=" $RUSTUP_TLS_CIPHERSUITES "
299+ return
300+ fi
301+
302+ local _openssl_syntax=" no"
303+ local _gnutls_syntax=" no"
304+ local _backend_supported=" yes"
305+ if curl -V | grep -q ' OpenSSL/' ; then
306+ _openssl_syntax=" yes"
307+ elif curl -V | grep -iq ' LibreSSL/' ; then
308+ _openssl_syntax=" yes"
309+ elif curl -V | grep -iq ' BoringSSL/' ; then
310+ _openssl_syntax=" yes"
311+ elif curl -V | grep -iq ' GnuTLS/' ; then
312+ _gnutls_syntax=" yes"
313+ else
314+ _backend_supported=" no"
315+ fi
316+
317+ local _args_supported=" no"
318+ if [ " $_backend_supported " = " yes" ]; then
319+ # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
320+ if check_help_for " notspecified" " curl" " --tlsv1.2" " --ciphers" " --proto" ; then
321+ _args_supported=" yes"
322+ fi
323+ fi
324+
325+ local _cs=" "
326+ if [ " $_args_supported " = " yes" ]; then
327+ if [ " $_openssl_syntax " = " yes" ]; then
328+ _cs=$( get_strong_ciphersuites_for " openssl" )
329+ elif [ " $_gnutls_syntax " = " yes" ]; then
330+ _cs=$( get_strong_ciphersuites_for " gnutls" )
331+ fi
332+ fi
333+
334+ RETVAL=" $_cs "
335+ }
336+
337+ # Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
338+ # if support by local tools is detected. Detection currently supports these wget backends:
339+ # GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
340+ get_ciphersuites_for_wget () {
341+ if [ -n " ${RUSTUP_TLS_CIPHERSUITES-} " ]; then
342+ # user specified custom cipher suites, assume they know what they're doing
343+ RETVAL=" $RUSTUP_TLS_CIPHERSUITES "
344+ return
345+ fi
346+
347+ local _cs=" "
348+ if wget -V | grep -q ' \-DHAVE_LIBSSL' ; then
349+ # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
350+ if check_help_for " notspecified" " wget" " TLSv1_2" " --ciphers" " --https-only" " --secure-protocol" ; then
351+ _cs=$( get_strong_ciphersuites_for " openssl" )
352+ fi
353+ elif wget -V | grep -q ' \-DHAVE_LIBGNUTLS' ; then
354+ # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
355+ if check_help_for " notspecified" " wget" " TLSv1_2" " --ciphers" " --https-only" " --secure-protocol" ; then
356+ _cs=$( get_strong_ciphersuites_for " gnutls" )
357+ fi
358+ fi
359+
360+ RETVAL=" $_cs "
361+ }
362+
363+ # Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2
364+ # excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad
365+ # DH params often found on servers (see RFC 7919). Sequence matches or is
366+ # similar to Firefox 68 ESR with weak cipher suites disabled via about:config.
367+ # $1 must be openssl or gnutls.
368+ get_strong_ciphersuites_for () {
369+ if [ " $1 " = " openssl" ]; then
370+ # OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet.
371+ echo " TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
372+ elif [ " $1 " = " gnutls" ]; then
373+ # GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't.
374+ # Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order.
375+ echo " SECURE128:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM"
376+ fi
377+ }
378+
235379DFXVM_GITHUB_LATEST_RELEASE_ROOT=" ${DFXVM_GITHUB_LATEST_RELEASE_ROOT:- https:// github.com/ dfinity/ dfxvm/ releases/ latest/ download} "
236380DFX_VERSION=" ${DFX_VERSION-} "
237381
@@ -252,14 +396,13 @@ download_and_install() {
252396 local _sha256_url=" ${_tarball_url} .sha256"
253397
254398 log " Downloading latest release..."
255- ensure downloader " $_tarball_url " " ${_tarball_filename} "
256- ensure downloader " $_sha256_url " " ${_sha256_filename} "
399+ ensure downloader " $_tarball_url " " ${_tarball_filename} " " $_arch "
400+ ensure downloader " $_sha256_url " " ${_sha256_filename} " " $_arch "
257401
258402 log " Checking integrity of tarball..."
259403 ensure " $SHASUM " -c " ${_sha256_filename} "
260404
261- ensure tar -xzf " ${_tarball_filename} "
262- ensure cd " ${_archive} " > /dev/null
405+ ensure tar -xzf " ${_tarball_filename} " --strip-components=1 " ${_archive} /dfxvm"
263406 ensure chmod u+x dfxvm
264407 ensure mv dfxvm dfxvm-init
265408
@@ -320,7 +463,9 @@ main() {
320463 )
321464 local _subshell_exit_code=$?
322465
323- ignore rm -rf " ${_dir} "
466+ ignore rm " ${_dir} " /dfxvm*
467+ ignore rmdir " ${_dir} "
468+
324469 exit $_subshell_exit_code
325470}
326471
0 commit comments