#!/bin/sh # # Radicle installation script. # set -e # SSH signing key for the release archives. This is currently cloudhead and fintan's keys. # FIXME: Technically, there should be a release signing key, with a shamir threshold of > 1, with the secret encrypted by something like SOPS. CLOUDHEAD="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL460KIEccS4881p7PPpiiQBsxF+H5tgC6De6crw9rbU" FINTAN="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEFsaRqAJ1r6bBFwlcWzJKN7DdjItQDumCNc0wqw6Dvk" LORENZ="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFhK7CqgIIbSthoNn8ea32krOnMzC807Z+PpBkR2YOVj" url() { echo "https://files.radicle.dev/releases/$1/radicle-$2.tar.xz" } info() { printf "\033[36m$*\033[0m\n" } warn() { printf "\033[33m$*\033[0m\n" } rad_home() { if command -v rad >/dev/null 2>&1; then rad path || true fi } is_authed() { RAD_HOME=$(rad_home) if [ -n "$RAD_HOME" ] && [ -f "$RAD_HOME/keys/radicle.pub" ]; then return 0 else return 1 fi } success() { version="$1" printf "\033[32m✓\033[0m Radicle \033[2m$1\033[0m was installed successfully.\n" RAD_HOME=$(rad_home) if [ -n "$RAD_HOME" ] && [ -S "$RAD_HOME/node/control.sock" ]; then printf "\n" printf "Please restart your node to complete the upgrade.\n" fi } error() { printf "\033[31merror\033[0m: $*\n" >&2 } fatal() { error "$@" exit 1 } usage() { echo "Usage" echo echo " $0 []" echo echo " This script will install the Radicle binaries under '$RAD_PATH'". echo " To change the location, set \$RAD_PATH to a different directory." echo echo " Your Radicle home is set to '$RAD_HOME'." echo " To change it, set \$RAD_HOME to a different directory." echo echo "Options" echo echo " --no-modify-path Do not modify the PATH environment variable" echo " --version=VERSION Install the given version of Radicle (default: latest)" echo " --prefix=PATH Radicle install prefix (default: ~/.radicle)" echo " --help, -h Show this help message and exit" echo echo "Environment" echo echo " RAD_HOME Radicle home directory" } target() { TARGET="" case "$(uname)/$(uname -m)" in Darwin/arm64) TARGET="aarch64-apple-darwin" ;; Darwin/x86_64) TARGET="x86_64-apple-darwin" ;; Linux/arm64|Linux/aarch64) TARGET="aarch64-unknown-linux-musl" ;; Linux/x86_64) TARGET="x86_64-unknown-linux-musl" ;; *) fatal "Your operating system is currently unsupported. Sorry!" ;; esac echo $TARGET } in_path() { IFS=":" for dir in $PATH; do if [ "$dir" = "$1" ]; then return 0 # The path is in $PATH fi done return 1 # The path is not in $PATH } get_started() { printf "\n" success "$@" if ! is_authed; then printf "\n" printf "Get started by creating your Radicle key pair with \033[35m\`rad auth\`\033[0m.\n" fi } verify() { archive="$1" signers="$(dirname $archive)/signers" # Add the signer key to the allowed signers file we pass to ssh-keygen. printf "radicle $CLOUDHEAD\n" > $signers printf "radicle $FINTAN\n" >> $signers printf "radicle $LORENZ\n" >> $signers # Verify that `$archive` was signed by a key in `$signers`, identified by the # pattern "*@radicle.dev", using the signature in `$archive.sig`. ssh-keygen -Y verify -f $signers -I "radicle" -n file -s "$archive.sig" < "$archive" || fatal "Invalid signature for $archive" } main() { PREFIX=${RAD_HOME:-"$HOME/.radicle"} SHELL_PATH=${SHELL:-"/bin/sh"} NO_MODIFY_PATH=false VERSION=latest if [ -n "$RAD_PATH" ]; then fatal "RAD_PATH is no longer supported; Use '--prefix' instead" fi if ! command -v tar >/dev/null 2>&1; then fatal "The 'tar' tool is required to extract the archive; please install 'tar' and try again" fi if ! command -v xz >/dev/null 2>&1; then fatal "The 'xz' tool is required to extract the archive; please install 'xz' or 'xz-utils' and try again" fi if ! command -v curl >/dev/null 2>&1; then fatal "The 'curl' tool is required to download the archive; please install 'curl' and try again" fi if ! command -v ssh-keygen >/dev/null 2>&1; then fatal "The 'ssh-keygen' tool is required to verify the archive; please install the 'openssh' and try again" fi while :; do case "$1" in --no-modify-path) NO_MODIFY_PATH=true ;; --prefix=*) PREFIX=${1#*=} ;; --version=*) VERSION=${1#*=} ;; -h|--help) usage exit 0 ;; -*) error "Unrecognized argument '$1'" echo ; usage ; exit 1 ;; *) break ;; esac shift done if [ -z "$VERSION" ]; then fatal "Empty version string; use --version=VERSION" fi if [ -z "$PREFIX" ]; then fatal "Empty installation prefix; use --prefix=PATH or set RAD_HOME" fi mkdir -p $PREFIX echo echo "👾 Welcome to Radicle" echo # Where to install binaries. RAD_PATH=$PREFIX/bin info "Detecting operating system..." TARGET=$(target) ARCHIVE="$(mktemp -d)/radicle-$TARGET.tar.xz" # Nb. `-d` must be used on BSDs. URL="$(url "$VERSION" "$TARGET")" info "Downloading $URL..." curl --proto '=https' --fail --tlsv1.2 -# -L "$URL" -o "$ARCHIVE" || fatal "Failed to fetch $URL" # Nb. `--tlsv1.3` is not supported on macOS info "Downloading $URL.sig..." curl --proto '=https' --fail --tlsv1.2 -# -L "$URL.sig" -o "$ARCHIVE.sig" || fatal "Failed to fetch $URL.sig" info "Verifying $(basename $ARCHIVE)..." verify "$ARCHIVE" info "Installing Radicle into $PREFIX..." tar -xJf "$ARCHIVE" --strip-components=1 -C "$PREFIX" chmod +x \ $RAD_PATH/radicle-node \ $RAD_PATH/rad \ $RAD_PATH/git-remote-rad if ! command -v git >/dev/null 2>&1; then warn warn "Warning: a Git installation was not detected on your system." warn "Warning: please install Git for Radicle to work correctly." fi version="$($RAD_PATH/rad --version | cut -f2 -d' ' -)" # If radicle is not in $PATH, add it here. if $NO_MODIFY_PATH; then info "Not modifying shell path variable, as requested." get_started $version elif in_path $RAD_PATH; then info "Radicle is configured in shell already, not modifying." get_started $version else PROFILE="" case $SHELL_PATH in */zsh) PROFILE=$HOME/.zshenv ;; */bash) PROFILE=$HOME/.bashrc ;; */fish) PROFILE=$HOME/.config/fish/config.fish ;; */ash) PROFILE=$HOME/.profile ;; */csh) PROFILE=$HOME/.cshrc ;; esac if [ -z "$PROFILE" ]; then warn "Warning: unable to update your PATH variable." warn "Warning: please manually add $RAD_PATH to your PATH." get_started $version else info "Configuring path variable in ~${PROFILE#$HOME}..." echo >> "$PROFILE" echo "# Added by Radicle." >> "$PROFILE" echo "export PATH=\"\$PATH:$RAD_PATH\"" >> "$PROFILE" echo success $version if command -v rad >/dev/null 2>&1; then EXISTING=$(command -v rad) printf "\n" warn "Warning: Pre-existing binaries found at $(dirname "$EXISTING")." warn "Warning: Installed new binaries in $RAD_PATH." fi printf "\n" printf "Before running Radicle for the first time,\n" printf "run \033[34m\`source ~${PROFILE#$HOME}\`\033[0m or open a new terminal.\n" if ! is_authed; then printf "\n" printf "Then, create your Radicle key pair with \033[35m\`rad auth\`\033[0m.\n" fi fi fi } main "$@"