diff --git a/lib/steps.sh b/lib/steps.sh index 49cc7c8..c5191b6 100755 --- a/lib/steps.sh +++ b/lib/steps.sh @@ -3,20 +3,15 @@ TOTAL_STEPS=6 -# ─── Variables globales ─────────────────────────────────────────────────────── -# Directorio base de hydra-veil HV_BASE="$HOME/.local/share/hydra-veil" -# Componentes HV_CORE="$HV_BASE/core" HV_CLI="$HV_BASE/cli" HV_GUI="$HV_BASE/gui" HV_ESSENTIALS="$HV_BASE/essentials" -# Venv — siempre en el core HV_VENV="$HV_CORE/.venv" -# XDG — INSTALL_DIR es $HOME, no el repo INSTALL_DIR="$HOME" HV_DATA_DIR="$HOME/data/hydra-veil" HV_CONFIG_DIR="$HOME/.config/hydra-veil" @@ -31,12 +26,10 @@ SINGBOX_CONFIG_DIR="$HV_DATA_DIR/configs" SINGBOX_PID_FILE="$HV_DATA_DIR/runtime/singbox.pid" SINGBOX_LOG_FILE="$HV_DATA_DIR/runtime/singbox.log" -# sudoers SUDOERS_PATH="/etc/sudoers.d/hydraveil" -# Repos declare -A REPO_URLS=( - ["core"]="https://git.simplifiedprivacy.com/Support/sp-hydra-veil-core " + ["core"]="https://git.simplifiedprivacy.com/Support/sp-hydra-veil-core" ["cli"]="https://git.simplifiedprivacy.com/Support/sp-hydra-veil-cli" ["essentials"]="https://git.simplifiedprivacy.com/Support/sp-essentials" ["gui"]="https://git.simplifiedprivacy.com/Support/sp-hydra-veil-gui" @@ -54,8 +47,6 @@ declare -A REPO_DIRS=( ["essentials"]="$HV_ESSENTIALS" ["gui"]="$HV_GUI" ) - -# ─── Importar steps atómicos ────────────────────────────────────────────────── _STEPS_DIR="$SCRIPT_DIR/lib/steps" for _step in preflight repos python_env singbox wrapper sudoers; do diff --git a/lib/steps/preflight.sh b/lib/steps/preflight.sh index 72747a3..994a044 100644 --- a/lib/steps/preflight.sh +++ b/lib/steps/preflight.sh @@ -1,6 +1,5 @@ #!/bin/bash # lib/steps/preflight.sh — verificaciones previas - step_preflight() { print_section "Pre-flight" log_step "System checks" 1 $TOTAL_STEPS diff --git a/lib/steps/python_env.sh b/lib/steps/python_env.sh index ee51652..60fa912 100644 --- a/lib/steps/python_env.sh +++ b/lib/steps/python_env.sh @@ -35,13 +35,11 @@ _create_venv() { _pip_install() { source "$HV_VENV/bin/activate" - # Fix: la GUI puede pedir core==2.3.4 pero core puede ser 2.3.x if [ -f "$HV_GUI/pyproject.toml" ]; then sed -i 's/sp-hydra-veil-core == [0-9.]*/sp-hydra-veil-core >= 2.3.0/' \ "$HV_GUI/pyproject.toml" 2>/dev/null || true fi - # Orden de instalación: dependencias primero for name in essentials core cli gui; do local dir case "$name" in diff --git a/lib/steps/repos.sh b/lib/steps/repos.sh index 07710d1..661bbfd 100644 --- a/lib/steps/repos.sh +++ b/lib/steps/repos.sh @@ -70,13 +70,11 @@ _setup_env() { *) _app_env="production" ;; esac - # SP_API_BASE_URL_PRODUCTION echo "" printf " ${BCYAN}┌─${RESET} ${BWHITE}SP_API_BASE_URL_PRODUCTION${RESET} ${DIM}e.g. https://fake.simplifiedprivacy.org/api/v1${RESET}\n" printf " ${BCYAN}›${RESET} " read -r _api_url < /dev/tty - # Escribir .env cat > "$env_file" << EOF APP_ENV=${_app_env} SP_API_BASE_URL_LOCAL=http://simplifiedprivacy.test/api/v1 diff --git a/pyproject.toml b/pyproject.toml index ed6412f..804ecad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ classifiers = [ ] dependencies = [ "cryptography ~= 46.0.3", + "python-dotenv ~= 1.0.0", "dataclasses-json ~= 0.6.7", "marshmallow ~= 3.26.1", "pysocks ~= 1.7.1", diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 01a6b02..0000000 --- a/requirements.txt +++ /dev/null @@ -1,31 +0,0 @@ -python-dotenv -cryptography~=46.0.3 -dataclasses-json~=0.6.7 -marshmallow~=3.26.1 -psutil~=7.1.3 -pysocks~=1.7.1 -python-dateutil~=2.9.0.post0 -requests~=2.32.5 -annotated-types==0.7.0 -certifi==2026.4.22 -charset-normalizer==3.4.7 -click==8.3.3 -cytoolz==1.1.0 -eth-hash==0.8.0 -eth-typing==6.0.0 -eth-utils==6.0.0 -idna==3.13 -packaging==26.2 -pathspec==1.1.1 -platformdirs==4.9.6 -py-ecc==8.0.0 -pydantic==2.13.3 -pydantic_core==2.46.3 -pydeps==3.0.6 -pytokens==0.4.1 -stdlib-list==0.12.0 -toolz==1.1.0 -typing-inspect==0.9.0 -typing-inspection==0.4.2 -typing_extensions==4.15.0 -urllib3==2.6.3 \ No newline at end of file diff --git a/uninstall.sh b/uninstall.sh index c5a9c43..d2f023c 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,113 +1,93 @@ #!/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' +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LIB_DIR="$SCRIPT_DIR/lib" -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 ""; } +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 -# ─── 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 ;; + --full|-f) FULL=true ;; + --yes|-y) YES=true ;; --help|-h) echo "" - echo " Uso: $0 [opciones]" + echo " Usage: $0 [options]" echo "" - echo " Sin flags — elimina wrapper, sudoers, logs, pid, run" - echo " conserva repo, venv y configs" + echo " No flags — removes wrapper, sudoers, runtime" + echo " keeps repos, venv, configs and data" echo "" - echo " --full — todo lo anterior + repo completo, venv y configs" - echo " --yes — no pide confirmación" + echo " --full — everything above + repos, venv, configs and data" + echo " --yes — skip confirmation prompt" echo "" exit 0 ;; *) - err "Flag desconocido: $arg" + log_error "Unknown flag: $arg" exit 1 ;; esac done -# ─── Banner ─────────────────────────────────────────────────────────────────── -echo "" -printf "${BOLD}${RED} hydra-veil — limpieza para reinstalación${RESET}\n" -echo "" +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 - warn "Modo --full: se eliminará TODO incluyendo repo, venv y configs" + label_warn "Mode --full: everything will be removed (repos, venv, configs, data)" else - info "Modo normal: conserva repo, venv y configs" + label_info "Normal mode: repos, venv, configs and data will be kept" + label_info "Use --full to remove everything" 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 "" + if ! ask_confirm "Continue with uninstall?"; then + log_warn "Uninstall cancelled." + exit 0 + fi fi -# ─── 1. Detener sing-box si está corriendo ──────────────────────────────────── -hdr "1. Proceso sing-box" +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="" - # 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..." + 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 @@ -117,149 +97,109 @@ _stop_singbox() { if kill -0 "$pid" 2>/dev/null; then kill -KILL "$pid" 2>/dev/null || true sleep 0.3 - ok "sing-box eliminado (SIGKILL)" + label_ok "sing-box killed (SIGKILL)" else - ok "sing-box detenido (SIGTERM)" + label_ok "sing-box stopped (SIGTERM)" fi else - info "sing-box no está corriendo" + label_info "sing-box is not running" 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 +if [ -x "$SINGBOX_WRAPPER" ]; then + sudo "$SINGBOX_WRAPPER" "" stop 2>/dev/null && label_ok "Stopped 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" + sudo ip link delete tun0 2>/dev/null && label_ok "tun0 removed" || label_warn "Could not remove tun0" else - info "tun0 no existe" + label_info "tun0 not found" fi -# ─── 2. Wrapper ─────────────────────────────────────────────────────────────── -hdr "2. Wrapper" +print_divider +print_section "2. Wrapper" -if [ -f "$WRAPPER_PATH" ]; then - sudo rm -f "$WRAPPER_PATH" - ok "Eliminado: $WRAPPER_PATH" +if [ -f "$SINGBOX_WRAPPER" ]; then + sudo rm -f "$SINGBOX_WRAPPER" + label_ok "Removed: $SINGBOX_WRAPPER" else - info "No existe: $WRAPPER_PATH" + label_info "Not found: $SINGBOX_WRAPPER" fi -# ─── 3. Sudoers ─────────────────────────────────────────────────────────────── -hdr "3. Sudoers" +print_divider +print_section "3. Sudoers" if [ -f "$SUDOERS_PATH" ]; then sudo rm -f "$SUDOERS_PATH" - ok "Eliminado: $SUDOERS_PATH" + label_ok "Removed: $SUDOERS_PATH" else - info "No existe: $SUDOERS_PATH" + label_info "Not found: $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:" + label_warn "Orphaned sudoers entries found:" echo "$_orphans" | while read -r f; do - warn " $f" - sudo rm -f "$f" && ok " Eliminado: $f" + sudo rm -f "$f" && label_ok " Removed: $f" done else - info "Sin entradas huérfanas en sudoers.d" + label_info "No orphaned entries in sudoers.d" fi -# ─── 4. PID file y runtime ──────────────────────────────────────────────────── -hdr "4. Runtime (pid / run)" +print_divider +print_section "4. Runtime" -if [ -f "$SINGBOX_PID_FILE" ]; then - rm -f "$SINGBOX_PID_FILE" - ok "Eliminado PID file: $SINGBOX_PID_FILE" -else - info "Sin PID file" -fi +_rm "$SINGBOX_PID_FILE" +_rm "$SINGBOX_LOG_FILE" +_rm "$HV_DATA_DIR/runtime" -if [ -d "$HV_RUN_DIR" ]; then - rm -rf "$HV_RUN_DIR" - ok "Eliminado: $HV_RUN_DIR" -else - info "No existe: $HV_RUN_DIR" -fi +print_divider -# ─── 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)" + print_section "5. Data" + _rm "$HV_DATA_DIR" - # Configs - if [ -d "$HV_CONFIG_DIR" ]; then - rm -rf "$HV_CONFIG_DIR" - ok "Eliminado: $HV_CONFIG_DIR" - else - info "No existe: $HV_CONFIG_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 - # 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" + label_ok "sing-box symlink removed: $SINGBOX_BIN" else - info "sing-box no es symlink — conservado: $SINGBOX_BIN" + label_info "sing-box is not a symlink — kept: $SINGBOX_BIN" fi + + print_divider fi -# ─── Resumen ────────────────────────────────────────────────────────────────── echo "" -printf "${BOLD}${GREEN} ✔ Limpieza completa.${RESET}" +label_ok "Uninstall complete" if $FULL; then - printf " ${DIM}(modo --full)${RESET}\n" + label_ok "Mode --full: everything removed" else - printf "\n" echo "" - printf " ${DIM}Conservados: repo, venv, configs${RESET}\n" - printf " ${DIM}Para eliminar todo: %s --full${RESET}\n" "$0" + label_info "Kept: repos, venv, configs, data" + label_info "To remove everything: $0 --full" fi echo "" -info "Podés correr el installer nuevamente sin conflictos." +print_divider echo ""