|
| 1 | +#!/bin/sh |
| 2 | +# shellcheck shell=dash |
| 3 | + |
| 4 | +set -eu |
| 5 | + |
| 6 | +PYTHON="${PYTHON:-}" |
| 7 | + |
| 8 | +get_python() { |
| 9 | + local _python |
| 10 | + if [ "$PYTHON" ]; then |
| 11 | + _python="$PYTHON" |
| 12 | + return |
| 13 | + fi |
| 14 | + _python=$(bash -c "compgen -c python" | grep '^python[2-3]\.[0-9]\+$' | head -n1) |
| 15 | + if [ "$_python" = "" ]; then |
| 16 | + echo "$0: error: did not find python installed" >&2 |
| 17 | + exit 1 |
| 18 | + fi |
| 19 | + RETVAL="$_python" |
| 20 | +} |
| 21 | + |
| 22 | +# FIXME: change this URL after installed will be properly uploaded. |
| 23 | +INSTALLER_URL="${INSTALLER_URL:-https://github.com/NilFoundation/zkllvm-rslang/releases/download/v0.0.1-beta/rslang-installer.py}" |
| 24 | + |
| 25 | +get_rslang_installer() { |
| 26 | + local _dir |
| 27 | + if ! _dir="$(ensure mktemp -d)"; then |
| 28 | + # Because the previous command ran in a subshell, we must manually |
| 29 | + # propagate exit status. |
| 30 | + exit 1 |
| 31 | + fi |
| 32 | + ensure mkdir -p "$_dir" |
| 33 | + |
| 34 | + local _url="${INSTALLER_URL}" |
| 35 | + local _file="${_dir}/rslang-installer.py" |
| 36 | + ensure downloader "$_url" "$_file" |
| 37 | + |
| 38 | + RETVAL="$_file" |
| 39 | +} |
| 40 | + |
| 41 | +say() { |
| 42 | + printf 'rslang-init: %s\n' "$1" |
| 43 | +} |
| 44 | + |
| 45 | +err() { |
| 46 | + say "$1" >&2 |
| 47 | + exit 1 |
| 48 | +} |
| 49 | + |
| 50 | +need_cmd() { |
| 51 | + if ! check_cmd "$1"; then |
| 52 | + err "need '$1' (command not found)" |
| 53 | + fi |
| 54 | +} |
| 55 | + |
| 56 | +check_cmd() { |
| 57 | + command -v "$1" > /dev/null 2>&1 |
| 58 | +} |
| 59 | + |
| 60 | +# Run a command that should never fail. If the command fails execution |
| 61 | +# will immediately terminate with an error showing the failing |
| 62 | +# command. |
| 63 | +ensure() { |
| 64 | + if ! "$@"; then err "command failed: $*"; fi |
| 65 | +} |
| 66 | + |
| 67 | +# This wraps curl or wget. Try curl first, if not installed, |
| 68 | +# use wget instead. |
| 69 | +downloader() { |
| 70 | + local _dld |
| 71 | + local _ciphersuites |
| 72 | + local _err |
| 73 | + local _status |
| 74 | + local _retry |
| 75 | + if check_cmd curl; then |
| 76 | + _dld=curl |
| 77 | + elif check_cmd wget; then |
| 78 | + _dld=wget |
| 79 | + else |
| 80 | + _dld='curl or wget' # to be used in error message of need_cmd |
| 81 | + fi |
| 82 | + |
| 83 | + if [ "$1" = --check ]; then |
| 84 | + need_cmd "$_dld" |
| 85 | + elif [ "$_dld" = curl ]; then |
| 86 | + check_curl_for_retry_support |
| 87 | + _retry="$RETVAL" |
| 88 | + get_ciphersuites_for_curl |
| 89 | + _ciphersuites="$RETVAL" |
| 90 | + echo "Downloading $1" >&2 |
| 91 | + if [ -n "$_ciphersuites" ]; then |
| 92 | + _err=$(curl $_retry --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2" 2>&1) |
| 93 | + _status=$? |
| 94 | + else |
| 95 | + echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure" |
| 96 | + if ! check_help_for "$3" curl --proto --tlsv1.2; then |
| 97 | + echo "Warning: Not enforcing TLS v1.2, this is potentially less secure" |
| 98 | + _err=$(curl $_retry --silent --show-error --fail --location "$1" --output "$2" 2>&1) |
| 99 | + _status=$? |
| 100 | + else |
| 101 | + _err=$(curl $_retry --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2" 2>&1) |
| 102 | + _status=$? |
| 103 | + fi |
| 104 | + fi |
| 105 | + if [ -n "$_err" ]; then |
| 106 | + echo "$_err" >&2 |
| 107 | + if echo "$_err" | grep -q 404$; then |
| 108 | + err "rslang for platform '$3' not found, this may be unsupported" |
| 109 | + fi |
| 110 | + fi |
| 111 | + return $_status |
| 112 | + elif [ "$_dld" = wget ]; then |
| 113 | + echo "Fetching $1" >&2 |
| 114 | + if [ "$(wget -V 2>&1|head -2|tail -1|cut -f1 -d" ")" = "BusyBox" ]; then |
| 115 | + echo "Warning: using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure" |
| 116 | + _err=$(wget "$1" -O "$2" 2>&1) |
| 117 | + _status=$? |
| 118 | + else |
| 119 | + get_ciphersuites_for_wget |
| 120 | + _ciphersuites="$RETVAL" |
| 121 | + if [ -n "$_ciphersuites" ]; then |
| 122 | + _err=$(wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2" 2>&1) |
| 123 | + _status=$? |
| 124 | + else |
| 125 | + echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure" |
| 126 | + if ! check_help_for "$3" wget --https-only --secure-protocol; then |
| 127 | + echo "Warning: Not enforcing TLS v1.2, this is potentially less secure" |
| 128 | + _err=$(wget "$1" -O "$2" 2>&1) |
| 129 | + _status=$? |
| 130 | + else |
| 131 | + _err=$(wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2" 2>&1) |
| 132 | + _status=$? |
| 133 | + fi |
| 134 | + fi |
| 135 | + fi |
| 136 | + if [ -n "$_err" ]; then |
| 137 | + echo "$_err" >&2 |
| 138 | + if echo "$_err" | grep -q ' 404 Not Found$'; then |
| 139 | + err "rslang for platform '$3' not found, this may be unsupported" |
| 140 | + fi |
| 141 | + fi |
| 142 | + return $_status |
| 143 | + else |
| 144 | + err "Unknown downloader" # should not reach here |
| 145 | + fi |
| 146 | +} |
| 147 | + |
| 148 | +check_help_for() { |
| 149 | + local _arch |
| 150 | + local _cmd |
| 151 | + local _arg |
| 152 | + _arch="$1" |
| 153 | + shift |
| 154 | + _cmd="$1" |
| 155 | + shift |
| 156 | + |
| 157 | + local _category |
| 158 | + if "$_cmd" --help | grep -q 'For all options use the manual or "--help all".'; then |
| 159 | + _category="all" |
| 160 | + else |
| 161 | + _category="" |
| 162 | + fi |
| 163 | + |
| 164 | + case "$_arch" in |
| 165 | + |
| 166 | + *darwin*) |
| 167 | + if check_cmd sw_vers; then |
| 168 | + case $(sw_vers -productVersion) in |
| 169 | + 10.*) |
| 170 | + # If we're running on macOS, older than 10.13, then we always |
| 171 | + # fail to find these options to force fallback |
| 172 | + if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then |
| 173 | + # Older than 10.13 |
| 174 | + echo "Warning: Detected macOS platform older than 10.13" |
| 175 | + return 1 |
| 176 | + fi |
| 177 | + ;; |
| 178 | + 11.*) |
| 179 | + # We assume Big Sur will be OK for now |
| 180 | + ;; |
| 181 | + *) |
| 182 | + # Unknown product version, warn and continue |
| 183 | + echo "Warning: Detected unknown macOS major version: $(sw_vers -productVersion)" |
| 184 | + echo "Warning TLS capabilities detection may fail" |
| 185 | + ;; |
| 186 | + esac |
| 187 | + fi |
| 188 | + ;; |
| 189 | + |
| 190 | + esac |
| 191 | + |
| 192 | + for _arg in "$@"; do |
| 193 | + if ! "$_cmd" --help "$_category" | grep -q -- "$_arg"; then |
| 194 | + return 1 |
| 195 | + fi |
| 196 | + done |
| 197 | + |
| 198 | + true # not strictly needed |
| 199 | +} |
| 200 | + |
| 201 | +# Check if curl supports the --retry flag, then pass it to the curl invocation. |
| 202 | +check_curl_for_retry_support() { |
| 203 | + local _retry_supported="" |
| 204 | + # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. |
| 205 | + if check_help_for "notspecified" "curl" "--retry"; then |
| 206 | + _retry_supported="--retry 3" |
| 207 | + if check_help_for "notspecified" "curl" "--continue-at"; then |
| 208 | + # "-C -" tells curl to automatically find where to resume the download when retrying. |
| 209 | + _retry_supported="--retry 3 -C -" |
| 210 | + fi |
| 211 | + fi |
| 212 | + |
| 213 | + RETVAL="$_retry_supported" |
| 214 | +} |
| 215 | + |
| 216 | +# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites |
| 217 | +# if support by local tools is detected. Detection currently supports these curl backends: |
| 218 | +# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty. |
| 219 | +get_ciphersuites_for_curl() { |
| 220 | + if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then |
| 221 | + # user specified custom cipher suites, assume they know what they're doing |
| 222 | + RETVAL="$RUSTUP_TLS_CIPHERSUITES" |
| 223 | + return |
| 224 | + fi |
| 225 | + |
| 226 | + local _openssl_syntax="no" |
| 227 | + local _gnutls_syntax="no" |
| 228 | + local _backend_supported="yes" |
| 229 | + if curl -V | grep -q ' OpenSSL/'; then |
| 230 | + _openssl_syntax="yes" |
| 231 | + elif curl -V | grep -iq ' LibreSSL/'; then |
| 232 | + _openssl_syntax="yes" |
| 233 | + elif curl -V | grep -iq ' BoringSSL/'; then |
| 234 | + _openssl_syntax="yes" |
| 235 | + elif curl -V | grep -iq ' GnuTLS/'; then |
| 236 | + _gnutls_syntax="yes" |
| 237 | + else |
| 238 | + _backend_supported="no" |
| 239 | + fi |
| 240 | + |
| 241 | + local _args_supported="no" |
| 242 | + if [ "$_backend_supported" = "yes" ]; then |
| 243 | + # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. |
| 244 | + if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then |
| 245 | + _args_supported="yes" |
| 246 | + fi |
| 247 | + fi |
| 248 | + |
| 249 | + local _cs="" |
| 250 | + if [ "$_args_supported" = "yes" ]; then |
| 251 | + if [ "$_openssl_syntax" = "yes" ]; then |
| 252 | + _cs=$(get_strong_ciphersuites_for "openssl") |
| 253 | + elif [ "$_gnutls_syntax" = "yes" ]; then |
| 254 | + _cs=$(get_strong_ciphersuites_for "gnutls") |
| 255 | + fi |
| 256 | + fi |
| 257 | + |
| 258 | + RETVAL="$_cs" |
| 259 | +} |
| 260 | + |
| 261 | +# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites |
| 262 | +# if support by local tools is detected. Detection currently supports these wget backends: |
| 263 | +# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty. |
| 264 | +get_ciphersuites_for_wget() { |
| 265 | + if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then |
| 266 | + # user specified custom cipher suites, assume they know what they're doing |
| 267 | + RETVAL="$RUSTUP_TLS_CIPHERSUITES" |
| 268 | + return |
| 269 | + fi |
| 270 | + |
| 271 | + local _cs="" |
| 272 | + if wget -V | grep -q '\-DHAVE_LIBSSL'; then |
| 273 | + # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. |
| 274 | + if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then |
| 275 | + _cs=$(get_strong_ciphersuites_for "openssl") |
| 276 | + fi |
| 277 | + elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then |
| 278 | + # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. |
| 279 | + if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then |
| 280 | + _cs=$(get_strong_ciphersuites_for "gnutls") |
| 281 | + fi |
| 282 | + fi |
| 283 | + |
| 284 | + RETVAL="$_cs" |
| 285 | +} |
| 286 | + |
| 287 | +# Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2 |
| 288 | +# excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad |
| 289 | +# DH params often found on servers (see RFC 7919). Sequence matches or is |
| 290 | +# similar to Firefox 68 ESR with weak cipher suites disabled via about:config. |
| 291 | +# $1 must be openssl or gnutls. |
| 292 | +get_strong_ciphersuites_for() { |
| 293 | + if [ "$1" = "openssl" ]; then |
| 294 | + # OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet. |
| 295 | + 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" |
| 296 | + elif [ "$1" = "gnutls" ]; then |
| 297 | + # GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't. |
| 298 | + # Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order. |
| 299 | + 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" |
| 300 | + fi |
| 301 | +} |
| 302 | + |
| 303 | +main() { |
| 304 | + downloader --check |
| 305 | + need_cmd mktemp |
| 306 | + |
| 307 | + ensure get_python |
| 308 | + local _python="$RETVAL" |
| 309 | + |
| 310 | + ensure get_rslang_installer |
| 311 | + local _script="$RETVAL" |
| 312 | + |
| 313 | + echo "Running installer" |
| 314 | + "$_python" "$_script" "$@" |
| 315 | + |
| 316 | + local _retval=$? |
| 317 | + return "$_retval" |
| 318 | +} |
| 319 | + |
| 320 | +main "$@" || exit 1 |
0 commit comments