Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add checksum verification to install script #24 #163

Merged
merged 1 commit into from
Aug 20, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 168 additions & 36 deletions install/tk.sh
Original file line number Diff line number Diff line change
@@ -1,51 +1,183 @@
#!/usr/bin/env bash

set -e

DEFAULT_BIN_DIR="/usr/local/bin"
BIN_DIR=${1:-"$DEFAULT_BIN_DIR"}

opsys=""
if [[ "$OSTYPE" == linux* ]]; then
opsys=linux
elif [[ "$OSTYPE" == darwin* ]]; then
opsys=darwin
fi

if [[ "$opsys" == "" ]]; then
echo "OS $OSTYPE not supported"
exit 1
fi

if [[ ! -x "$(command -v curl)" ]]; then
echo "curl not found"
BIN_DIR=${1:-"${DEFAULT_BIN_DIR}"}
GITHUB_REPO="fluxcd/toolkit"

# Helper functions for logs
info() {
echo '[INFO] ' "$@"
}

warn() {
echo '[WARN] ' "$@" >&2
}

fatal() {
echo '[ERROR] ' "$@" >&2
exit 1
fi
}

tmpDir=`mktemp -d`
if [[ ! "$tmpDir" || ! -d "$tmpDir" ]]; then
echo "could not create temp dir"
exit 1
fi
# Set os, fatal if operating system not supported
setup_verify_os() {
if [[ -z "${OS}" ]]; then
OS=$(uname)
fi
case ${OS} in
Darwin)
OS=darwin
;;
Linux)
OS=linux
;;
*)
fatal "Unsupported operating system ${OS}"
esac
}

function cleanup {
rm -rf "$tmpDir"
# Set arch, fatal if architecture not supported
setup_verify_arch() {
if [[ -z "${ARCH}" ]]; then
ARCH=$(uname -m)
fi
case ${ARCH} in
amd64)
ARCH=amd64
;;
x86_64)
ARCH=amd64
;;
*)
fatal "Unsupported architecture ${ARCH}"
esac
}

trap cleanup EXIT
# Verify existence of downloader executable
verify_downloader() {
# Return failure if it doesn't exist or is no executable
[[ -x "$(which "$1")" ]] || return 1

pushd $tmpDir >& /dev/null
# Set verified executable as our downloader program and return success
DOWNLOADER=$1
return 0
}

curl -s https://api.github.com/repos/fluxcd/toolkit/releases/latest |\
grep browser_download |\
grep $opsys |\
cut -d '"' -f 4 |\
xargs curl -sL -o tk.tar.gz
# Create tempory directory and cleanup when done
setup_tmp() {
TMP_DIR=$(mktemp -d -t tk-install.XXXXXXXXXX)
TMP_METADATA="${TMP_DIR}/tk.json"
TMP_HASH="${TMP_DIR}/tk.hash"
TMP_BIN="${TMP_DIR}/tk.tar.gz"
cleanup() {
code=$?
set +e
trap - EXIT
rm -rf "${TMP_DIR}"
exit ${code}
}
trap cleanup INT EXIT
}

tar xzf ./tk.tar.gz
# Find version from Github metadata
get_release_version() {
METADATA_URL="https://api.github.com/repos/${GITHUB_REPO}/releases/latest"

mv ./tk $BIN_DIR
info "Downloading metadata ${METADATA_URL}"
download "${TMP_METADATA}" "${METADATA_URL}"

popd >& /dev/null
VERSION_TK=$(grep '"tag_name":' "${TMP_METADATA}" | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
if [[ -n "${VERSION_TK}" ]]; then
info "Using ${VERSION_TK} as release"
else
fatal "Unable to determine release version"
fi
}

echo "$(tk --version) installed"
# Download from file from URL
download() {
[[ $# -eq 2 ]] || fatal 'download needs exactly 2 arguments'

case $DOWNLOADER in
curl)
curl -o "$1" -sfL "$2"
;;
wget)
wget -qO "$1" "$2"
;;
*)
fatal "Incorrect executable '${DOWNLOADER}'"
;;
esac

# Abort if download command failed
[[ $? -eq 0 ]] || fatal 'Download failed'
}

# Download hash from Github URL
download_hash() {
HASH_URL="https://github.com/${GITHUB_REPO}/releases/download/v${VERSION_TK}/toolkit_${VERSION_TK}_checksums.txt"
info "Downloading hash ${HASH_URL}"
download "${TMP_HASH}" "${HASH_URL}"
HASH_EXPECTED=$(grep " tk_${VERSION_TK}_${OS}_${ARCH}.tar.gz$" "${TMP_HASH}")
HASH_EXPECTED=${HASH_EXPECTED%%[[:blank:]]*}
}

# Download binary from Github URL
download_binary() {
BIN_URL="https://github.com/${GITHUB_REPO}/releases/download/v${VERSION_TK}/tk_${VERSION_TK}_${OS}_${ARCH}.tar.gz"
info "Downloading binary ${BIN_URL}"
download "${TMP_BIN}" "${BIN_URL}"
}

compute_sha256sum() {
cmd=$(which sha256sum shasum | head -n 1)
case $(basename "$cmd") in
sha256sum)
sha256sum "$1" | cut -f 1 -d ' '
;;
shasum)
shasum -a 256 "$1" | cut -f 1 -d ' '
;;
*)
fatal "Can not find sha256sum or shasum to compute checksum"
;;
esac
}

# Verify downloaded binary hash
verify_binary() {
info "Verifying binary download"
HASH_BIN=$(compute_sha256sum "${TMP_BIN}")
HASH_BIN=${HASH_BIN%%[[:blank:]]*}
if [[ "${HASH_EXPECTED}" != "${HASH_BIN}" ]]; then
fatal "Download sha256 does not match ${HASH_EXPECTED}, got ${HASH_BIN}"
fi
}

# Setup permissions and move binary
setup_binary() {
chmod 755 "${TMP_BIN}"
info "Installing tk to ${BIN_DIR}/tk"
tar -xzf "${TMP_BIN}" -C "${TMP_DIR}"

local CMD_MOVE="mv -f \"${TMP_DIR}/tk\" \"${BIN_DIR}\""
if [[ -w "${BIN_DIR}" ]]; then
eval "${CMD_MOVE}"
else
eval "sudo ${CMD_MOVE}"
fi
}

# Run the install process
{
setup_verify_os
setup_verify_arch
verify_downloader curl || verify_downloader wget || fatal 'Can not find curl or wget for downloading files'
setup_tmp
get_release_version
download_hash
download_binary
verify_binary
setup_binary
}