#!/usr/bin/env bash # ============================================================================= # Personal Internet Cell (PIC) — Bash Installer # ============================================================================= # # SECURITY NOTICE # --------------- # You are about to execute this script with elevated privileges. # ALWAYS review a script before running it: # # curl -fsSL https://git.pic.ngo/roof/pic/raw/branch/main/install.sh | less # # SHA256 checksum (verify before running): # PLACEHOLDER — updated when script is published at git.pic.ngo # # Verify with: # sha256sum install.sh # # or, via curl before piping: # curl -fsSL https://git.pic.ngo/roof/pic/raw/branch/main/install.sh \ # | sha256sum # # ============================================================================= # # Usage: # sudo bash install.sh # Standard install # sudo bash install.sh --force # Bypass idempotency check # sudo PIC_DIR=/srv/pic bash install.sh # Custom install directory # # Supported OS: Debian/Ubuntu (apt), Fedora/RHEL (dnf), Alpine Linux (apk) # # ============================================================================= set -euo pipefail # --------------------------------------------------------------------------- # Configuration # --------------------------------------------------------------------------- PIC_DIR="${PIC_DIR:-/opt/pic}" PIC_REPO="${PIC_REPO:-https://git.pic.ngo/roof/pic.git}" PIC_USER="${PIC_USER:-pic}" API_HEALTH_URL="http://127.0.0.1:3000/health" API_HEALTH_TIMEOUT=60 WEBUI_PORT=8081 FORCE=0 # Parse flags for arg in "$@"; do case "$arg" in --force) FORCE=1 ;; *) echo "Unknown argument: $arg" >&2 echo "Usage: $0 [--force]" >&2 exit 1 ;; esac done # --------------------------------------------------------------------------- # Color output # --------------------------------------------------------------------------- if [ -t 1 ] && command -v tput >/dev/null 2>&1 && tput setaf 1 >/dev/null 2>&1; then RED="$(tput setaf 1)" GREEN="$(tput setaf 2)" YELLOW="$(tput setaf 3)" BOLD="$(tput bold)" RESET="$(tput sgr0)" else RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BOLD='\033[1m' RESET='\033[0m' fi log_step() { printf "\n${BOLD}[%s/%s] %s${RESET}\n" "$1" "$TOTAL_STEPS" "$2"; } log_ok() { printf " ${GREEN}✓${RESET} %s\n" "$1"; } log_warn() { printf " ${YELLOW}⚠${RESET} %s\n" "$1"; } log_error() { printf "\n${RED}${BOLD}ERROR:${RESET}${RED} %s${RESET}\n" "$1" >&2; } die() { log_error "$1"; exit 1; } # --------------------------------------------------------------------------- # Interactive prompt helpers (use /dev/tty so they work even with piped stdin) # --------------------------------------------------------------------------- prompt() { # prompt