Skip to content

Commit 16515a8

Browse files
chore(dfxvm-installer): install script maintenance (#3566)
* remove get_tag_from_manifest_json * remove unused function * copy check_help_for and downloader from rustup * rework tarball extraction to avoid rm -rf
1 parent 8f84fda commit 16515a8

File tree

1 file changed

+216
-71
lines changed

1 file changed

+216
-71
lines changed

public/install-dfxvm.sh

Lines changed: 216 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,6 @@
1111
##
1212
set -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.
3315
DFX_BOOL_FLAGS=""
3416

@@ -111,7 +93,6 @@ err() {
11193
say "$1" >&2
11294
exit 1
11395
}
114-
## 110_assert.sh
11596

11697
need_cmd() {
11798
if ! check_cmd "$1"; then
@@ -144,61 +125,81 @@ ignore() {
144125
define_flag_BOOL "insecure" "Allows downloading from insecure URLs, either using HTTP or TLS 1.2 or less."
145126

146127
check_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.
200194
downloader() {
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+
235379
DFXVM_GITHUB_LATEST_RELEASE_ROOT="${DFXVM_GITHUB_LATEST_RELEASE_ROOT:-https://github.com/dfinity/dfxvm/releases/latest/download}"
236380
DFX_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

Comments
 (0)