#!/bin/bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LIB_DIR="$SCRIPT_DIR/lib" for _lib in ui log input steps; do _path="$LIB_DIR/${_lib}.sh" if [ ! -f "$_path" ]; then echo "[ERROR] Missing lib: $_path" >&2 exit 1 fi source "$_path" done FULL=false YES=false for arg in "$@"; do case "$arg" in --full|-f) FULL=true ;; --yes|-y) YES=true ;; --help|-h) echo "" echo " Usage: $0 [options]" echo "" echo " No flags — removes wrapper, sudoers, runtime" echo " keeps repos, venv, configs and data" echo "" echo " --full — everything above + repos, venv, configs and data" echo " --yes — skip confirmation prompt" echo "" exit 0 ;; *) log_error "Unknown flag: $arg" exit 1 ;; esac done clear print_header "HYDRA-VEIL UNINSTALLER" "v2.0.0" printf " ${DIM}%s${RESET}\n" "$(date '+%Y-%m-%d %H:%M:%S') — $(uname -n)" print_divider if $FULL; then label_warn "Mode --full: everything will be removed (repos, venv, configs, data)" else label_info "Normal mode: repos, venv, configs and data will be kept" label_info "Use --full to remove everything" fi echo "" if ! $YES; then if ! ask_confirm "Continue with uninstall?"; then log_warn "Uninstall cancelled." exit 0 fi fi print_divider _rm() { local target="$1" if [ -e "$target" ]; then rm -rf "$target" label_ok "Removed: $target" else label_info "Not found: $target" fi } print_section "1. sing-box process" _stop_singbox() { local pid="" if [ -f "$SINGBOX_PID_FILE" ]; then pid=$(cat "$SINGBOX_PID_FILE" 2>/dev/null || echo "") fi 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 log_info "Stopping 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 label_ok "sing-box killed (SIGKILL)" else label_ok "sing-box stopped (SIGTERM)" fi else label_info "sing-box is not running" fi } if [ -x "$SINGBOX_WRAPPER" ]; then sudo "$SINGBOX_WRAPPER" "" stop 2>/dev/null && label_ok "Stopped via wrapper" || _stop_singbox else _stop_singbox fi if ip link show tun0 &>/dev/null 2>&1; then sudo ip link delete tun0 2>/dev/null && label_ok "tun0 removed" || label_warn "Could not remove tun0" else label_info "tun0 not found" fi print_divider print_section "2. Wrapper" if [ -f "$SINGBOX_WRAPPER" ]; then sudo rm -f "$SINGBOX_WRAPPER" label_ok "Removed: $SINGBOX_WRAPPER" else label_info "Not found: $SINGBOX_WRAPPER" fi print_divider print_section "3. Sudoers" if [ -f "$SUDOERS_PATH" ]; then sudo rm -f "$SUDOERS_PATH" label_ok "Removed: $SUDOERS_PATH" else label_info "Not found: $SUDOERS_PATH" fi _orphans=$(sudo grep -rl "hydraveil" /etc/sudoers.d/ 2>/dev/null || true) if [ -n "$_orphans" ]; then label_warn "Orphaned sudoers entries found:" echo "$_orphans" | while read -r f; do sudo rm -f "$f" && label_ok " Removed: $f" done else label_info "No orphaned entries in sudoers.d" fi print_divider print_section "4. Runtime" _rm "$SINGBOX_PID_FILE" _rm "$SINGBOX_LOG_FILE" _rm "$HV_DATA_DIR/runtime" print_divider if $FULL; then print_section "5. Data" _rm "$HV_DATA_DIR" print_section "6. Configs" _rm "$HV_CONFIG_DIR" _rm "$HV_CACHE_DIR" _rm "$HV_STATE_DIR" print_section "7. Venv" _rm "$HV_VENV" print_section "8. Repos" for _dir in "$HV_CORE" "$HV_CLI" "$HV_GUI" "$HV_ESSENTIALS"; do _rm "$_dir" done if [ -d "$HV_BASE" ] && [ -z "$(ls -A "$HV_BASE" 2>/dev/null)" ]; then rmdir "$HV_BASE" label_ok "Empty base directory removed: $HV_BASE" fi if [ -L "$SINGBOX_BIN" ]; then sudo rm -f "$SINGBOX_BIN" label_ok "sing-box symlink removed: $SINGBOX_BIN" else label_info "sing-box is not a symlink — kept: $SINGBOX_BIN" fi print_divider fi echo "" label_ok "Uninstall complete" if $FULL; then label_ok "Mode --full: everything removed" else echo "" label_info "Kept: repos, venv, configs, data" label_info "To remove everything: $0 --full" fi echo "" print_divider echo ""