#!/usr/bin/env sh # Bootstrap: curl -fsSL https://install.visudo.icu | sh # Supports: curl -fsSL | sh -s -- [install.sh flags...] set -eu # --- Colors (POSIX-safe, respects NO_COLOR) --- if [ -n "${NO_COLOR:-}" ] || [ ! -t 1 ]; then RED='' GREEN='' DIM='' NC='' else RED='\033[0;31m' GREEN='\033[0;32m' DIM='\033[2m' NC='\033[0m' fi info() { printf " %b●%b %s\n" "$GREEN" "$NC" "$*"; } error() { printf " %b●%b %s\n" "$RED" "$NC" "$*" >&2; } # --- Preflight --- if [ "$(id -u)" = "0" ]; then error "Do not run this as root" exit 1 fi if [ "$(uname)" != "Linux" ]; then error "This installer only supports Linux" exit 1 fi if ! command -v bash >/dev/null 2>&1; then error "bash is required" exit 1 fi if ! command -v curl >/dev/null 2>&1; then error "curl is required — install it first, then re-run" exit 1 fi # --- Parse arguments (preserve quoting via positional params) --- BASE_URL="${DOTFILES_URL:-https://install.visudo.icu}" DOTFILES_DIR="$HOME/.dotfiles" # POSIX sh has no arrays — use a sentinel to rebuild $@ in place, preserving # quoting/whitespace through the final `exec bash … "$@"`. Forwarded args # are appended past the sentinel; the loop stops when it reaches it. _argv_sentinel="__BOOTSTRAP_ARGV_END__" set -- "$@" "$_argv_sentinel" while [ "$1" != "$_argv_sentinel" ]; do case "$1" in --dir|-d) [ $# -ge 2 ] || { error "$1 requires a value"; exit 1; } DOTFILES_DIR="$2" shift 2 ;; *) # Rotate this arg past the sentinel — it will be forwarded to install.sh. set -- "$@" "$1" shift ;; esac done shift # drop the sentinel; $@ is now exactly what we forward. # --- Download and verify (with retry for CDN cache skew) --- info "Downloading dotfiles..." tmpdir=$(mktemp -d) trap 'rm -rf "$tmpdir"' EXIT # Fetch the tarball + checksum and compare. Returns 0 on match, 1 on mismatch, # 2 on hard failure (download/parse error). On mismatch we retry once with # cache-busting query strings to recover from CDN edge cache skew between # `.tar.gz` and `.tar.gz.sha256` during a deploy propagation window. fetch_and_verify() { suffix="${1:-}" tar_url="$BASE_URL/dotfiles.tar.gz$suffix" sum_url="$BASE_URL/dotfiles.tar.gz.sha256$suffix" if ! curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \ "$tar_url" -o "$tmpdir/dotfiles.tar.gz"; then error "Failed to download dotfiles from $tar_url" return 2 fi if ! curl -fsSL --connect-timeout 5 -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \ "$sum_url" -o "$tmpdir/expected.sha256" 2>/dev/null; then error "Checksum file not available — cannot verify download integrity" error "If this persists, download manually from $BASE_URL" return 2 fi expected_checksum=$(awk '{print $1; exit}' "$tmpdir/expected.sha256") # Validate that the checksum file actually contains a SHA-256 (64 hex chars). # Without this, a CDN serving the wrong content (e.g. an HTML error page or the # wrong asset) would be silently accepted as a checksum. if ! printf '%s' "$expected_checksum" | grep -qE '^[0-9a-fA-F]{64}$'; then error "Checksum file at $sum_url is malformed" error "(server returned non-SHA-256 content — try again or report to maintainer)" return 2 fi actual_checksum=$(sha256sum "$tmpdir/dotfiles.tar.gz" | awk '{print $1}') if [ "$expected_checksum" != "$actual_checksum" ]; then return 1 fi return 0 } if fetch_and_verify ""; then info "Checksum verified" else rc=$? if [ "$rc" = "2" ]; then exit 1 fi # Mismatch — likely CDN cache skew between the two assets. Retry once with # a cache-busting query string to force the edge to revalidate both files. info "Checksum mismatch — refreshing cache and retrying..." sleep 2 if fetch_and_verify "?cb=$(date +%s)-$$"; then info "Checksum verified" else error "Checksum verification failed — download may be corrupted or tampered with" printf " Expected: %s\n" "$expected_checksum" >&2 printf " Got: %s\n" "$actual_checksum" >&2 error "If this persists after a few minutes, report it: $BASE_URL" exit 1 fi fi # --- Extract --- if [ -d "$DOTFILES_DIR" ]; then info "Existing install found at $DOTFILES_DIR — updating..." rm -rf "$DOTFILES_DIR" fi mkdir -p "$DOTFILES_DIR" if ! tar -xzf "$tmpdir/dotfiles.tar.gz" -C "$DOTFILES_DIR"; then error "Failed to extract dotfiles" exit 1 fi # --- Verify download integrity --- if [ ! -f "$DOTFILES_DIR/install.sh" ]; then error "Download appears corrupted — install.sh not found in $DOTFILES_DIR" exit 1 fi # --- Launch installer --- info "Launching installer..." if [ $# -gt 0 ]; then printf " %b%s %s%b\n\n" "$DIM" "$DOTFILES_DIR/install.sh" "$*" "$NC" else printf " %b%s%b\n\n" "$DIM" "$DOTFILES_DIR/install.sh" "$NC" fi exec bash "$DOTFILES_DIR/install.sh" "$@"