#!/bin/bash # hv-clean.sh — Limpieza completa de hydra-veil para reinstalación limpia # Elimina: wrapper, sudoers, dirs de runtime (logs/run/pid) # Conserva: repo, venv, configs (a menos que se pase --full) set -euo pipefail # ─── Colores ────────────────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' DIM='\033[2m' BOLD='\033[1m' RESET='\033[0m' ok() { printf " ${GREEN}✔${RESET} %s\n" "$*"; } warn() { printf " ${YELLOW}⚠${RESET} %s\n" "$*"; } info() { printf " ${CYAN}→${RESET} %s\n" "$*"; } err() { printf " ${RED}✖${RESET} %s\n" "$*" >&2; } hdr() { echo ""; printf "${BOLD}${CYAN}── %s ${RESET}\n" "$*"; echo ""; } # ─── Paths (deben coincidir con steps.sh) ──────────────────────────────────── HV_CORE_HOME="$HOME/.local/share/hydra-veil/core" HV_LOG_DIR="$HV_CORE_HOME/logs/hydra-veil" HV_RUN_DIR="$HV_CORE_HOME/run" HV_DATA_DIR="$HV_CORE_HOME/data/hydra-veil" HV_CONFIG_DIR="$HV_DATA_DIR/configs" HV_VENV_DIR="$HV_CORE_HOME/.venv" SINGBOX_BIN="/usr/bin/sing-box" SINGBOX_PID_FILE="$HV_RUN_DIR/singbox.pid" SINGBOX_LOG_FILE="$HV_LOG_DIR/singbox.log" WRAPPER_PATH="/usr/local/bin/hydraveil-singbox" SUDOERS_PATH="/etc/sudoers.d/hydraveil" # ─── Flags ──────────────────────────────────────────────────────────────────── FULL=false YES=false for arg in "$@"; do case "$arg" in --full|-f) FULL=true ;; --yes|-y) YES=true ;; --help|-h) echo "" echo " Uso: $0 [opciones]" echo "" echo " Sin flags — elimina wrapper, sudoers, logs, pid, run" echo " conserva repo, venv y configs" echo "" echo " --full — todo lo anterior + repo completo, venv y configs" echo " --yes — no pide confirmación" echo "" exit 0 ;; *) err "Flag desconocido: $arg" exit 1 ;; esac done # ─── Banner ─────────────────────────────────────────────────────────────────── echo "" printf "${BOLD}${RED} hydra-veil — limpieza para reinstalación${RESET}\n" echo "" if $FULL; then warn "Modo --full: se eliminará TODO incluyendo repo, venv y configs" else info "Modo normal: conserva repo, venv y configs" fi echo "" # ─── Confirmación ───────────────────────────────────────────────────────────── if ! $YES; then printf " ${YELLOW}¿Continuar?${RESET} ${DIM}[s/N]:${RESET} " read -r _confirm < /dev/tty case "$_confirm" in s|S|y|Y) : ;; *) echo "" info "Cancelado." exit 0 ;; esac echo "" fi # ─── 1. Detener sing-box si está corriendo ──────────────────────────────────── hdr "1. Proceso sing-box" _stop_singbox() { local pid="" # Intentar via pidfile primero if [ -f "$SINGBOX_PID_FILE" ]; then pid=$(cat "$SINGBOX_PID_FILE" 2>/dev/null || echo "") fi # Si no hay pidfile, buscar por nombre if [[ -z "$pid" || ! "$pid" =~ ^[0-9]+$ ]]; then pid=$(pgrep -x sing-box 2>/dev/null | head -1 || echo "") fi if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]] && kill -0 "$pid" 2>/dev/null; then info "Deteniendo sing-box PID $pid..." kill -TERM "$pid" 2>/dev/null || true local elapsed=0 while kill -0 "$pid" 2>/dev/null && (( elapsed < 16 )); do sleep 0.5 (( elapsed++ )) || true done if kill -0 "$pid" 2>/dev/null; then kill -KILL "$pid" 2>/dev/null || true sleep 0.3 ok "sing-box eliminado (SIGKILL)" else ok "sing-box detenido (SIGTERM)" fi else info "sing-box no está corriendo" fi } # Intentar via wrapper si existe, sino directo if [ -x "$WRAPPER_PATH" ]; then sudo "$WRAPPER_PATH" "" stop 2>/dev/null && ok "Detenido via wrapper" || _stop_singbox else _stop_singbox fi # Eliminar interfaz tun0 si existe if ip link show tun0 &>/dev/null 2>&1; then sudo ip link delete tun0 2>/dev/null && ok "tun0 eliminada" || warn "No se pudo eliminar tun0" else info "tun0 no existe" fi # ─── 2. Wrapper ─────────────────────────────────────────────────────────────── hdr "2. Wrapper" if [ -f "$WRAPPER_PATH" ]; then sudo rm -f "$WRAPPER_PATH" ok "Eliminado: $WRAPPER_PATH" else info "No existe: $WRAPPER_PATH" fi # ─── 3. Sudoers ─────────────────────────────────────────────────────────────── hdr "3. Sudoers" if [ -f "$SUDOERS_PATH" ]; then sudo rm -f "$SUDOERS_PATH" ok "Eliminado: $SUDOERS_PATH" else info "No existe: $SUDOERS_PATH" fi # Verificar que no haya entradas huérfanas en sudoers.d _orphans=$(sudo grep -rl "hydraveil" /etc/sudoers.d/ 2>/dev/null || true) if [ -n "$_orphans" ]; then warn "Entradas huérfanas de hydraveil encontradas:" echo "$_orphans" | while read -r f; do warn " $f" sudo rm -f "$f" && ok " Eliminado: $f" done else info "Sin entradas huérfanas en sudoers.d" fi # ─── 4. PID file y runtime ──────────────────────────────────────────────────── hdr "4. Runtime (pid / run)" if [ -f "$SINGBOX_PID_FILE" ]; then rm -f "$SINGBOX_PID_FILE" ok "Eliminado PID file: $SINGBOX_PID_FILE" else info "Sin PID file" fi if [ -d "$HV_RUN_DIR" ]; then rm -rf "$HV_RUN_DIR" ok "Eliminado: $HV_RUN_DIR" else info "No existe: $HV_RUN_DIR" fi # ─── 5. Logs ────────────────────────────────────────────────────────────────── hdr "5. Logs" if [ -d "$HV_LOG_DIR" ]; then rm -rf "$HV_LOG_DIR" ok "Eliminado: $HV_LOG_DIR" else info "No existe: $HV_LOG_DIR" fi # ─── 6. Limpieza completa (--full) ──────────────────────────────────────────── if $FULL; then hdr "6. Limpieza completa (--full)" # Configs if [ -d "$HV_CONFIG_DIR" ]; then rm -rf "$HV_CONFIG_DIR" ok "Eliminado: $HV_CONFIG_DIR" else info "No existe: $HV_CONFIG_DIR" fi # Data dir completo if [ -d "$HV_DATA_DIR" ]; then rm -rf "$HV_DATA_DIR" ok "Eliminado: $HV_DATA_DIR" else info "No existe: $HV_DATA_DIR" fi # Venv if [ -d "$HV_VENV_DIR" ]; then rm -rf "$HV_VENV_DIR" ok "Eliminado venv: $HV_VENV_DIR" else info "No existe: $HV_VENV_DIR" fi # Repo completo if [ -d "$HV_CORE_HOME/.git" ]; then rm -rf "$HV_CORE_HOME" ok "Eliminado repo: $HV_CORE_HOME" elif [ -d "$HV_CORE_HOME" ]; then rm -rf "$HV_CORE_HOME" ok "Eliminado directorio: $HV_CORE_HOME" else info "No existe: $HV_CORE_HOME" fi # sing-box binary (solo si se instaló por el installer, no si era preexistente) if [ -L "$SINGBOX_BIN" ]; then sudo rm -f "$SINGBOX_BIN" ok "Eliminado symlink sing-box: $SINGBOX_BIN" else info "sing-box no es symlink — conservado: $SINGBOX_BIN" fi fi # ─── Resumen ────────────────────────────────────────────────────────────────── echo "" printf "${BOLD}${GREEN} ✔ Limpieza completa.${RESET}" if $FULL; then printf " ${DIM}(modo --full)${RESET}\n" else printf "\n" echo "" printf " ${DIM}Conservados: repo, venv, configs${RESET}\n" printf " ${DIM}Para eliminar todo: %s --full${RESET}\n" "$0" fi echo "" info "Podés correr el installer nuevamente sin conflictos." echo ""