#!/bin/sh # Installs the parity CLI: # curl --proto '=https' --tlsv1.2 -fsSL https://parity.ninja/install | sh # PARITY_VERSION picks another version (default: the one below). # PARITY_INSTALL_DIR sets where it goes (default: /usr/local/bin if # writable, else ~/.local/bin). # # The checksums of the default version and the release public key are # written into this script at release (infra/release-cli.sh). The script is # served from parity.ninja while the binaries come from a separate bucket, # so a tampered bucket alone can't install anything: the default version is # checked against the checksums below, any other version against its # SHA256SUMS, whose signature is checked against the key below (needs # openssl). Everything runs from main at the very end, so a download cut # short runs nothing. set -eu # BEGIN RELEASE (infra/release-cli.sh rewrites this block) PARITY_LATEST="v0.1.0" PARITY_SUMS=" 6f078c11c42a534483c7e78156e3b000a933ecda170e5e80272ce93bb8e66af4 parity_darwin_amd64 8193de964bafd735b846c2071874d7ec067b70eb0b9d805a7105a26e0686f373 parity_darwin_arm64 aeb56dcf60472b79654e1e107d3b9785171b1eb8350e586b1c3b35245c42573d parity_linux_amd64 1a41bc6277a3247fb0e9b9bbefdf1f395b474cf2f5abbeefc36bca4b002c1ad0 parity_linux_arm64 d24d4b3c3e4e266ed0c786c2c949547118f8776e6e3094478fb1c62e46def1ea parity_windows_amd64.exe e7d0953d3f41517acca850cd909f31abcf88fc64450873e56be8ba073f94c2dd parity_windows_arm64.exe " PARITY_PUBKEY=" -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMIafppwdjkxGeaiW8h5imNHuViIs aDUQiXye2J1flaOlYXamO/zFmkVOaJ4Ya2Rg7DscubCxDx2tIrbrOMRoPg== -----END PUBLIC KEY----- " # END RELEASE BASE=https://storage.googleapis.com/parity-releases/parity say() { printf 'parity: %s\n' "$*" >&2; } die() { say "$*"; exit 1; } fetch() { if command -v curl >/dev/null 2>&1; then curl --proto '=https' --tlsv1.2 -fsSL --retry 3 "$1" elif command -v wget >/dev/null 2>&1; then wget -qO- "$1" # every URL here is https; busybox wget has no --https-only else die "needs curl or wget" fi } sha256() { if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1 elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | cut -d' ' -f1 else die "needs sha256sum or shasum to check the download" fi } # Checks $tmp/SHA256SUMS against its signature and the key above. verify() { [ -n "$PARITY_PUBKEY" ] || { say "no release key yet: $1 is checked against the bucket's checksums only"; return; } command -v openssl >/dev/null 2>&1 || die "needs openssl to check the signature of $1 (or install the default version)" fetch "$BASE/$1/SHA256SUMS.sig" > "$tmp/SHA256SUMS.sig" || die "release $1 has no signature: refusing to install" printf '%s\n' "$PARITY_PUBKEY" > "$tmp/release.pub" openssl dgst -sha256 -verify "$tmp/release.pub" -signature "$tmp/SHA256SUMS.sig" "$tmp/SHA256SUMS" >/dev/null 2>&1 || die "bad signature on release $1: refusing to install" } main() { case "$(uname -s)" in Linux) os=linux ;; Darwin) os=darwin ;; *) die "unsupported OS $(uname -s): Linux and macOS are supported" ;; esac case "$(uname -m)" in x86_64 | amd64) arch=amd64 ;; arm64 | aarch64) arch=arm64 ;; *) die "unsupported CPU $(uname -m): amd64 and arm64 are supported" ;; esac # A shell under Rosetta reports x86_64 on Apple Silicon; install the native binary. if [ "$os" = darwin ] && [ "$(sysctl -n sysctl.proc_translated 2>/dev/null)" = 1 ]; then arch=arm64; fi name="parity_${os}_${arch}" version=${PARITY_VERSION:-$PARITY_LATEST} [ -n "$version" ] || die "no release yet" case "$version" in v[0-9]*) ;; *) die "PARITY_VERSION=$version: want a version such as v0.1.0" ;; esac tmp=$(mktemp -d) part= trap 'rm -rf "$tmp" ${part:+"$part"}' EXIT trap 'exit 130' INT TERM if [ "$version" = "$PARITY_LATEST" ]; then sums=$PARITY_SUMS else fetch "$BASE/$version/SHA256SUMS" > "$tmp/SHA256SUMS" || die "no release $version" verify "$version" sums=$(cat "$tmp/SHA256SUMS") fi want=$(printf '%s\n' "$sums" | awk -v n="$name" '$2 == n { print $1 }') [ -n "$want" ] || die "no $name in release $version" say "downloading $version for $os/$arch" fetch "$BASE/$version/$name" > "$tmp/parity" || die "download failed" got=$(sha256 "$tmp/parity") [ "$got" = "$want" ] || die "checksum mismatch for $name $version: refusing to install" dir=${PARITY_INSTALL_DIR:-} if [ -z "$dir" ]; then if [ -w /usr/local/bin ]; then dir=/usr/local/bin; else dir="$HOME/.local/bin"; fi fi mkdir -p "$dir" || die "can't create $dir: set PARITY_INSTALL_DIR" # Copy next to the target, then rename: a replace is atomic even when # $tmp is on another filesystem. part="$dir/.parity.$$" cp "$tmp/parity" "$part" || die "can't write to $dir: set PARITY_INSTALL_DIR" chmod 755 "$part" mv -f "$part" "$dir/parity" || die "can't replace $dir/parity" part= say "installed $version to $dir/parity" case ":$PATH:" in *":$dir:"*) found=$(command -v parity 2>/dev/null || true) if [ -n "$found" ] && [ "$found" != "$dir/parity" ]; then say "$found comes first on your PATH; remove it or put $dir first" fi ;; *) say "$dir is not on your PATH. Add this line to your shell's startup file (~/.zshrc, ~/.bashrc):" printf ' export PATH="%s:$PATH"\n' "$dir" >&2 ;; esac } main "$@"