#!/usr/bin/env bash # # Hound installer. # # curl -fsSL https://get.houndav.com | bash # # What it does: # 1. Detects the system (Debian/Ubuntu/Mint vs Fedora/RHEL vs Arch) # 2. Downloads the latest .deb package # 3. Verifies the SHA-256 checksum # 4. Installs via the system package manager # # What it does NOT do: # - Run without asking. Every destructive step is explained first. # - Touch anything outside /usr/bin, /var/lib/hound, and the systemd unit. # - Phone home beyond downloading the package. # - Install as root silently. It uses sudo and you authenticate. # set -euo pipefail DL_BASE="https://dl.houndav.com" LATEST_URL="${DL_BASE}/latest.json" # ── Helpers ──────────────────────────────────────────────────────── bold() { printf '\033[1m%s\033[0m' "$*"; } green() { printf '\033[32m%s\033[0m' "$*"; } red() { printf '\033[31m%s\033[0m' "$*"; } dim() { printf '\033[2m%s\033[0m' "$*"; } info() { printf ' %s %s\n' "$(green '→')" "$*"; } warn() { printf ' %s %s\n' "$(red '!')" "$*"; } step() { printf '\n %s\n' "$(bold "$*")"; } die() { warn "$@"; exit 1; } need() { command -v "$1" >/dev/null 2>&1 || die "$1 is required but not found." } # ── Detect platform ─────────────────────────────────────────────── detect_distro() { if [ -f /etc/os-release ]; then . /etc/os-release case "${ID:-}" in ubuntu|debian|linuxmint|pop|elementary|zorin|neon) FAMILY="debian" ;; fedora|rhel|centos|rocky|alma|ol) FAMILY="rpm" ;; arch|manjaro|endeavouros|garuda) FAMILY="arch" ;; *) # Check ID_LIKE as fallback case "${ID_LIKE:-}" in *debian*|*ubuntu*) FAMILY="debian" ;; *fedora*|*rhel*) FAMILY="rpm" ;; *arch*) FAMILY="arch" ;; *) FAMILY="unknown" ;; esac ;; esac DISTRO_NAME="${PRETTY_NAME:-${ID:-unknown}}" else FAMILY="unknown" DISTRO_NAME="unknown" fi } detect_arch() { case "$(uname -m)" in x86_64|amd64) ARCH="amd64" ;; aarch64|arm64) ARCH="arm64" ;; *) die "Unsupported architecture: $(uname -m). Hound currently supports x86_64." ;; esac } # ── Fetch latest release info ───────────────────────────────────── fetch_latest() { need curl LATEST=$(curl -fsSL "$LATEST_URL") || die "Could not reach ${LATEST_URL}" VERSION=$(printf '%s' "$LATEST" | grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | cut -d'"' -f4) DEB_URL=$(printf '%s' "$LATEST" | grep -o '"deb_url"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | cut -d'"' -f4) DEB_SHA=$(printf '%s' "$LATEST" | grep -o '"deb_sha256"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | cut -d'"' -f4) [ -n "$VERSION" ] || die "Could not parse version from latest.json" [ -n "$DEB_URL" ] || die "Could not parse download URL from latest.json" [ -n "$DEB_SHA" ] || die "Could not parse checksum from latest.json" } # ── Check for existing install ──────────────────────────────────── check_existing() { if command -v hound >/dev/null 2>&1; then INSTALLED=$(hound --version 2>/dev/null | head -1 || echo "unknown") info "Hound is already installed: $(dim "$INSTALLED")" if printf '%s' "$INSTALLED" | grep -q "$VERSION"; then info "You already have the latest version (${VERSION})." printf '\n Reinstall anyway? [y/N] ' read -r ans case "$ans" in y|Y|yes|YES) ;; *) info "Nothing to do."; exit 0 ;; esac else info "Upgrading to ${VERSION}." fi fi } # ── Install methods ─────────────────────────────────────────────── install_deb() { need curl need sha256sum local tmp tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT local deb="${tmp}/hound_${VERSION}_${ARCH}.deb" step "Downloading Hound ${VERSION}" info "From: $(dim "$DEB_URL")" curl -fSL --progress-bar -o "$deb" "$DEB_URL" step "Verifying checksum" local actual actual=$(sha256sum "$deb" | cut -d' ' -f1) if [ "$actual" != "$DEB_SHA" ]; then warn "Checksum mismatch!" warn " Expected: ${DEB_SHA}" warn " Got: ${actual}" die "The download may be corrupted. Try again, or download manually from dl.houndav.com." fi info "SHA-256: $(dim "$actual") $(green '✓')" step "Installing" info "This will use sudo to install the package." sudo dpkg -i "$deb" || sudo apt-get install -f -y printf '\n' info "$(green 'Hound installed successfully.')" } # ── Main ────────────────────────────────────────────────────────── main() { printf '\n' printf ' %s\n' "$(bold 'Hound Installer')" printf ' %s\n\n' "$(dim 'https://houndav.com')" detect_distro detect_arch fetch_latest info "Detected: $(dim "$DISTRO_NAME") (${FAMILY}, ${ARCH})" info "Latest: $(bold "Hound ${VERSION}")" check_existing case "$FAMILY" in debian) install_deb ;; rpm) warn "RPM packages are coming soon." info "Build from source: $(dim 'https://github.com/HoundAV/hound-antivirus')" exit 1 ;; arch) warn "AUR package is coming soon." info "Build from source: $(dim 'https://github.com/HoundAV/hound-antivirus')" exit 1 ;; *) warn "Could not detect your distribution." info "Hound currently supports Debian, Ubuntu, and Linux Mint." info "Build from source: $(dim 'https://github.com/HoundAV/hound-antivirus')" exit 1 ;; esac printf '\n %s\n' "$(bold 'Quick start:')" printf ' %s\n' "$(dim ' hound status — check the daemon')" printf ' %s\n' "$(dim ' hound scan ~/Downloads — scan a directory')" printf ' %s\n\n' "$(dim ' sudo hound settings exec-gate on — enable real-time blocking')" } main "$@"