Script : install_tech_tools.sh

#!/usr/bin/env bash
# =============================================================================
#  install_tech_tools.sh
#  Installation d'outils Tech sur Debian / Ubuntu
#
#  Usage :
#    chmod +x install_tech_tools.sh
#    sudo ./install_tech_tools.sh [--dry-run] [--section SECTION]
#
#  Options :
#    --dry-run            Affiche les commandes sans les exécuter
#    --section SECTION    N'installe qu'une section (ex: network, forensics, devops…)
#    --help               Affiche cette aide
#
#  Sections disponibles :
#    maintenance  |  network  |  devops  |  filesystems  |  misc
#    password     |  forensics|  backup  |  remote       |  virtualization
#    anonymization|  ai       |  osint
# =============================================================================

set -euo pipefail

# ─── Couleurs ────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GRN='\033[0;32m'; YLW='\033[1;33m'
BLU='\033[0;34m'; CYN='\033[0;36m'; BOLD='\033[1m'; RST='\033[0m'

DRY_RUN=false
SECTION_FILTER=""
LOG_FILE="/var/log/tech_tools_install_$(date +%Y%m%d_%H%M%S).log"

# ─── Détection de la distribution ────────────────────────────────────────────
DISTRO_ID=$(. /etc/os-release && echo "${ID}")
DISTRO_ID_LIKE=$(. /etc/os-release && echo "${ID_LIKE:-}")
DISTRO_CODENAME=$(. /etc/os-release && echo "${VERSION_CODENAME:-${UBUNTU_CODENAME:-}}")
IS_DEBIAN=false
IS_UBUNTU=false
if [[ "$DISTRO_ID" == "debian" ]]; then
  IS_DEBIAN=true
elif [[ "$DISTRO_ID" == "ubuntu" || "$DISTRO_ID" == "pop" || "$DISTRO_ID_LIKE" == *"ubuntu"* ]]; then
  IS_UBUNTU=true
  DISTRO_CODENAME=$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$DISTRO_CODENAME}")
fi

# ─── Parsing arguments ───────────────────────────────────────────────────────
usage() {
  grep '^#  ' "$0" | sed 's/#  //'
  exit 0
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --dry-run)   DRY_RUN=true; shift ;;
    --section)   SECTION_FILTER="$2"; shift 2 ;;
    --help|-h)   usage ;;
    *)           echo "Option inconnue : $1"; usage ;;

  esac
done

# ─── Helpers ─────────────────────────────────────────────────────────────────
info()    { echo -e "${BLU}[INFO]${RST}  $*" | tee -a "$LOG_FILE"; }
success() { echo -e "${GRN}[OK]${RST}    $*" | tee -a "$LOG_FILE"; }
warn()    { echo -e "${YLW}[WARN]${RST}  $*" | tee -a "$LOG_FILE"; }
error()   { echo -e "${RED}[ERR]${RST}   $*" | tee -a "$LOG_FILE"; }
title()   { echo -e "\n${BOLD}${CYN}══════════ $* ══════════${RST}" | tee -a "$LOG_FILE"; }

apt_install() {
  local section="$1"; shift
  local pkgs=("$@")
  if [[ -n "$SECTION_FILTER" && "$section" != "$SECTION_FILTER" ]]; then return; fi

  info "Installation section : ${BOLD}${section}${RST} (${#pkgs[@]} paquets)"
  local available=()
  local missing=()

  for pkg in "${pkgs[@]}"; do
    if apt-cache show "$pkg" &>/dev/null 2>&1; then
      available+=("$pkg")
    else
      missing+=("$pkg")
    fi
  done

  if [[ ${#missing[@]} -gt 0 ]]; then
    warn "Paquets non trouvés dans les dépôts (ignorés) : ${missing[*]}"
  fi

  if [[ ${#available[@]} -eq 0 ]]; then
    warn "Aucun paquet disponible pour la section $section."
    return
  fi

  if $DRY_RUN; then
    echo -e "${YLW}[DRY-RUN]${RST} apt-get install -y ${available[*]}"
  else
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      "${available[@]}" 2>&1 | tee -a "$LOG_FILE" || warn "Certains paquets ont échoué dans $section"
    success "Section $section terminée."
  fi
}

# ─── Vérifications ───────────────────────────────────────────────────────────
if [[ $EUID -ne 0 ]] && ! $DRY_RUN; then
  error "Ce script doit être exécuté en root (sudo)."
  exit 1
fi

title "Tech Tools Installer"
info "Distribution : $DISTRO_ID ($DISTRO_CODENAME)"
info "Log : $LOG_FILE"
info "Mode dry-run : $DRY_RUN"
[[ -n "$SECTION_FILTER" ]] && info "Filtre section : $SECTION_FILTER"

# ─── Mise à jour des dépôts ──────────────────────────────────────────────────
if [[ -z "$SECTION_FILTER" ]] || [[ "$SECTION_FILTER" == "update" ]]; then
  title "Mise à jour des dépôts APT"
  if ! $DRY_RUN; then
    apt-get update -qq | tee -a "$LOG_FILE"
  else
    echo "[DRY-RUN] apt-get update"
  fi
fi

# ─── Ajout des dépôts tiers nécessaires ─────────────────────────────────────
setup_repos() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "repos" ]]; then return; fi
  title "Configuration des dépôts tiers"

  # Docker
  if ! command -v docker &>/dev/null; then
    local docker_distro="debian"
    local docker_codename="$DISTRO_CODENAME"
    if $IS_UBUNTU; then
      docker_distro="ubuntu"
    fi
    info "Ajout dépôt Docker ($docker_distro/$docker_codename)..."
    if ! $DRY_RUN; then
      curl -fsSL "https://download.docker.com/linux/${docker_distro}/gpg" \
        | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
      echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/${docker_distro} ${docker_codename} stable" \
        > /etc/apt/sources.list.d/docker.list
    else
      echo "[DRY-RUN] Ajout dépôt Docker ($docker_distro)"
    fi
  fi

  # Ansible PPA (Ubuntu uniquement) / paquet Debian standard
  if ! command -v ansible &>/dev/null; then
    if $IS_UBUNTU; then
      info "Ajout PPA Ansible..."
      if ! $DRY_RUN; then
        add-apt-repository -y ppa:ansible/ansible 2>&1 | tee -a "$LOG_FILE" || true
      else
        echo "[DRY-RUN] add-apt-repository ppa:ansible/ansible"
      fi
    else
      info "Ansible sera installé depuis les dépôts Debian standard."
    fi
  fi

  # WireGuard (inclus dans le kernel 5.6+)
  info "WireGuard est inclus dans le kernel 5.6+ — aucun dépôt nécessaire."

  # Dépôts supplémentaires selon la distribution
  if $IS_UBUNTU; then
    info "Activation dépôts universe + multiverse..."
    if ! $DRY_RUN; then
      add-apt-repository -y universe 2>&1 | tee -a "$LOG_FILE" || true
      add-apt-repository -y multiverse 2>&1 | tee -a "$LOG_FILE" || true
    else
      echo "[DRY-RUN] activation universe + multiverse"
    fi
  elif $IS_DEBIAN; then
    info "Activation dépôts contrib + non-free..."
    if ! $DRY_RUN; then
      if ! grep -qE "contrib|non-free" /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null; then
        sed -i 's/^deb \(.*\) main$/deb \1 main contrib non-free non-free-firmware/' /etc/apt/sources.list 2>/dev/null || true
      fi
    else
      echo "[DRY-RUN] activation contrib + non-free"
    fi
  fi

  if ! $DRY_RUN; then apt-get update -qq | tee -a "$LOG_FILE"; fi
  success "Dépôts configurés."
}

setup_repos

# ═══════════════════════════════════════════════════════════════════════════════
#  1. MAINTENANCE — DISKS & HARDWARE
# ═══════════════════════════════════════════════════════════════════════════════
title "1. Maintenance — Disques & Hardware"

apt_install "maintenance" \
  e2fsprogs baobab diskscan disktype gpart gsmartcontrol hdparm ioping testdisk \
  ncdu smartmontools di util-linux iotop iozone3 nvme-cli \
  cpulimit dmidecode fio hardinfo lshw pcp stress stress-ng \
  memtester inxi sysstat hwdata \
  chkrootkit clamtk rkhunter clamav clamav-daemon clamav-freshclam \
  xsensors lm-sensors psensor

# ═══════════════════════════════════════════════════════════════════════════════
#  2. CLONAGE & SAUVEGARDE DISQUE
# ═══════════════════════════════════════════════════════════════════════════════
title "2. Clonage & Sauvegarde disque"

apt_install "backup_disk" \
  clonezilla dcfldd dc3dd fsarchiver partclone partimage guymager

# ═══════════════════════════════════════════════════════════════════════════════
#  3. OUTILS DE MOT DE PASSE & CRYPTOGRAPHIE
# ═══════════════════════════════════════════════════════════════════════════════
title "3. Password Tools"

apt_install "password" \
  bruteforce-luks chntpw cmospwd fcrackzip hashcat hydra \
  john ophcrack ophcrack-cli pdfcrack rarcrack samdump2 crunch

# ═══════════════════════════════════════════════════════════════════════════════
#  4. PARTITIONNEMENT & EFFACEMENT
# ═══════════════════════════════════════════════════════════════════════════════
title "4. Partitionnement & Effacement sécurisé"

apt_install "partitioning" \
  fatresize fdisk gdisk gparted nwipe parted secure-delete wipe \
  zerofree bleachbit scrub util-linux

# ═══════════════════════════════════════════════════════════════════════════════
#  5. PROTECTION DES DONNÉES
# ═══════════════════════════════════════════════════════════════════════════════
title "5. Protection des données"

apt_install "data_protection" \
  fscrypt lockfile-progs zulucrypt-cli zulucrypt-gui \
  zulumount-cli zulumount-gui cryptsetup

# ═══════════════════════════════════════════════════════════════════════════════
#  6. RÉCUPÉRATION DE DONNÉES (FORENSICS)
# ═══════════════════════════════════════════════════════════════════════════════
title "6. Récupération de données & Forensics"

apt_install "forensics" \
  gddrescue ddrescueview ext4magic extundelete foremost testdisk \
  magicrescue myrescue recoverdm recoverjpeg safecopy scalpel \
  sleuthkit autopsy

# ═══════════════════════════════════════════════════════════════════════════════
#  7. FICHIERS DUPLIQUÉS
# ═══════════════════════════════════════════════════════════════════════════════
title "7. Fichiers dupliqués"

apt_install "duplicates" \
  dupeguru fdupes rdfind

# ═══════════════════════════════════════════════════════════════════════════════
#  8. RÉSEAU — DHCP / DNS / IP / Ethernet
# ═══════════════════════════════════════════════════════════════════════════════
title "8. Réseau — DHCP / DNS / IP / Ethernet"

apt_install "network_base" \
  dhcpdump dhcping \
  dnsenum mdns-scan whois bind9-dnsutils \
  ethstatus ethtool \
  net-tools ipcalc sipcalc iproute2 iptraf-ng ipv6calc \
  traceroute iputils-tracepath ndisc6

# ═══════════════════════════════════════════════════════════════════════════════
#  9. RÉSEAU — Monitoring & Capture
# ═══════════════════════════════════════════════════════════════════════════════
title "9. Réseau — Monitoring & Capture réseau"

apt_install "network_monitoring" \
  cbm etherape ifstat iftop iperf iperf3 nethogs sockstat tcpstat \
  darkstat ngrep pcapfix scapy python3-scapy tcpdump tcpreplay \
  tcpxtract tshark wireshark

# ═══════════════════════════════════════════════════════════════════════════════
#  10. RÉSEAU — Scanners & Pentest réseau
# ═══════════════════════════════════════════════════════════════════════════════
title "10. Réseau — Scanners & Outils pentest"

apt_install "network_scan" \
  arp-scan arpalert iputils-arping arptables arpwatch macchanger \
  bettercap driftnet dsniff ettercap-graphical lft masscan \
  mitmproxy mtr-tiny netdiscover netsniff-ng ncat nmap telnet \
  traceroute netcat-openbsd tcpflow tcptrace tcptraceroute

# ═══════════════════════════════════════════════════════════════════════════════
#  11. SSL/TLS
# ═══════════════════════════════════════════════════════════════════════════════
title "11. SSL/TLS Analysis"

apt_install "ssl_tls" \
  ssldump sslsplit sslscan

# ═══════════════════════════════════════════════════════════════════════════════
#  12. WI-FI
# ═══════════════════════════════════════════════════════════════════════════════
title "12. Wi-Fi"

apt_install "wifi" \
  aircrack-ng iw rfkill linssid

# ═══════════════════════════════════════════════════════════════════════════════
#  13. VPN
# ═══════════════════════════════════════════════════════════════════════════════
title "13. VPN"

apt_install "vpn" \
  openvpn wireguard openfortivpn \
  network-manager-openvpn network-manager-openconnect \
  network-manager-openvpn-gnome network-manager-openconnect-gnome

# ═══════════════════════════════════════════════════════════════════════════════
#  14. ANONYMISATION — TOR & ANONSURF
# ═══════════════════════════════════════════════════════════════════════════════
title "14. Anonymisation — Tor & AnonSurf"

apt_install "anonymization" \
  tor torsocks torbrowser-launcher obfs4proxy nyx macchanger iptables

# ─── AnonSurf (transparent proxy via Tor) ────────────────────────────────────
install_anonsurf() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "anonymization" ]]; then return; fi

  if command -v anonsurf &>/dev/null; then
    info "AnonSurf déjà installé — passage."
    return
  fi

  info "Installation d'AnonSurf (transparent Tor proxy)..."

  if $DRY_RUN; then
    echo "[DRY-RUN] Clone + compilation + installation AnonSurf"
    return
  fi

  local ANONSURF_SRC="/opt/anonsurf"

  # Cloner si pas déjà présent
  if [[ ! -d "$ANONSURF_SRC/.git" ]]; then
    info "Clonage du dépôt AnonSurf..."
    git clone https://github.com/ParrotSec/anonsurf.git "$ANONSURF_SRC" 2>&1 | tee -a "$LOG_FILE" || {
      warn "AnonSurf : clonage échoué"; return
    }
  else
    info "Sources AnonSurf trouvées dans $ANONSURF_SRC"
  fi

  # Installer Nim si nécessaire (pour compiler dnstool et make-torrc)
  if ! command -v nim &>/dev/null; then
    info "Installation du compilateur Nim..."
    DEBIAN_FRONTEND=noninteractive apt-get install -y nim 2>&1 | tee -a "$LOG_FILE" || {
      warn "Nim : installation échouée — AnonSurf ne peut pas être compilé"; return
    }
  fi

  # Compiler les binaires essentiels
  local BUILD_DIR
  BUILD_DIR=$(mktemp -d /tmp/anonsurf-build.XXXXX)
  info "Compilation de dnstool..."
  if ! nim c --out:"$BUILD_DIR/dnstool" -d:release "$ANONSURF_SRC/src/nim/dnstool/dnstool.nim" 2>&1 | tee -a "$LOG_FILE"; then
    warn "AnonSurf : compilation dnstool échouée"; rm -rf "$BUILD_DIR"; return
  fi

  info "Compilation de make-torrc..."
  if ! nim c --out:"$BUILD_DIR/make-torrc" -d:release "$ANONSURF_SRC/src/nim/anonsurf/make_torrc.nim" 2>&1 | tee -a "$LOG_FILE"; then
    warn "AnonSurf : compilation make-torrc échouée"; rm -rf "$BUILD_DIR"; return
  fi

  # Créer les répertoires
  mkdir -p /etc/anonsurf /usr/lib/anonsurf /etc/network

  # Installer les binaires compilés
  install -m 755 "$BUILD_DIR/dnstool"    /usr/bin/dnstool
  install -m 755 "$BUILD_DIR/make-torrc" /usr/lib/anonsurf/make-torrc
  rm -rf "$BUILD_DIR"

  # Installer les scripts daemon
  install -m 755 "$ANONSURF_SRC/scripts/anondaemon" /usr/lib/anonsurf/anondaemon
  install -m 755 "$ANONSURF_SRC/scripts/safekill"   /usr/lib/anonsurf/safekill

  # Installer les configs
  cp "$ANONSURF_SRC/configs/bridges.txt"  /etc/anonsurf/
  cp "$ANONSURF_SRC/configs/onion.pac"    /etc/anonsurf/
  cp "$ANONSURF_SRC/configs/torrc.base"   /etc/anonsurf/

  # Installer le service systemd
  cp "$ANONSURF_SRC/sys-units/anonsurfd.service" /lib/systemd/system/anonsurfd.service
  systemctl daemon-reload

  # Créer le CLI wrapper (le binaire Nim CLI nécessite gintro/GTK non dispo facilement)
  cat > /usr/bin/anonsurf << 'EOFCLI'
#!/bin/bash
# AnonSurf CLI — wrapper bash (remplace le binaire Nim pour systèmes non-ParrotOS)
RED='\033[0;31m'; GRN='\033[0;32m'; YLW='\033[1;33m'
BLU='\033[0;34m'; CYN='\033[0;36m'; BOLD='\033[1m'; RST='\033[0m'

show_help() {
  echo -e "\n${BOLD}${CYN}AnonSurf — Transparent proxy through Tor${RST}\n"
  echo -e "  ${BLU}Usage:${RST} sudo anonsurf {start|stop|restart|changeid|status|myip|help}\n"
  echo -e "  ${GRN}start${RST}         Démarrer AnonSurf (routage Tor transparent)"
  echo -e "  ${GRN}stop${RST}          Arrêter AnonSurf (trafic normal)"
  echo -e "  ${GRN}restart${RST}       Redémarrer AnonSurf"
  echo -e "  ${GRN}changeid${RST}      Changer d'identité Tor (nouveau circuit)"
  echo -e "  ${GRN}status${RST}        État d'AnonSurf et Tor"
  echo -e "  ${GRN}myip${RST}          Afficher l'IP publique actuelle"
  echo -e "  ${GRN}enable-boot${RST}   Activer AnonSurf au démarrage"
  echo -e "  ${GRN}disable-boot${RST}  Désactiver AnonSurf au démarrage"
  echo ""
}

check_root() {
  if [[ $(id -u) -ne 0 ]]; then
    echo -e "[${RED}!${RST}] Droits root requis. Utilisez sudo."; exit 1
  fi
}

do_start() {
  check_root
  if systemctl is-active --quiet anonsurfd 2>/dev/null; then
    echo -e "[${YLW}!${RST}] AnonSurf est déjà actif."; return; fi
  echo -e "[${GRN}*${RST}]${BLU} Démarrage d'AnonSurf...${RST}"
  systemctl start anonsurfd
  if systemctl is-active --quiet anonsurfd 2>/dev/null; then
    echo -e "[${GRN}*${RST}] AnonSurf démarré."; sleep 2; do_myip
  else
    echo -e "[${RED}!${RST}] Échec du démarrage."; journalctl -u anonsurfd --no-pager -n 10; fi
}

do_stop() {
  check_root
  if ! systemctl is-active --quiet anonsurfd 2>/dev/null; then
    echo -e "[${YLW}!${RST}] AnonSurf n'est pas actif."; return; fi
  echo -e "[${GRN}*${RST}]${BLU} Arrêt d'AnonSurf...${RST}"
  systemctl stop anonsurfd
  echo -e "[${GRN}*${RST}] AnonSurf arrêté."
}

do_restart() {
  check_root
  echo -e "[${GRN}*${RST}]${BLU} Redémarrage d'AnonSurf...${RST}"
  systemctl restart anonsurfd; sleep 2
  if systemctl is-active --quiet anonsurfd 2>/dev/null; then
    echo -e "[${GRN}*${RST}] AnonSurf redémarré."; do_myip
  else echo -e "[${RED}!${RST}] Échec du redémarrage."; fi
}

do_changeid() {
  if ! systemctl is-active --quiet anonsurfd 2>/dev/null; then
    echo -e "[${RED}!${RST}] AnonSurf n'est pas actif."; return; fi
  echo -e "[${GRN}*${RST}]${BLU} Nouvelle identité Tor...${RST}"
  killall -HUP tor 2>/dev/null; sleep 3; do_myip
}

do_status() {
  echo -e "\n${BOLD}${CYN}=== État AnonSurf ===${RST}"
  if systemctl is-active --quiet anonsurfd 2>/dev/null; then
    echo -e "[${GRN}*${RST}] AnonSurf : ${GRN}ACTIF${RST}"
  else echo -e "[${RED}*${RST}] AnonSurf : ${RED}INACTIF${RST}"; fi
  if systemctl is-active --quiet tor 2>/dev/null || systemctl is-active --quiet tor@default 2>/dev/null; then
    echo -e "[${GRN}*${RST}] Tor :      ${GRN}ACTIF${RST}"
  else echo -e "[${RED}*${RST}] Tor :      ${RED}INACTIF${RST}"; fi
  if systemctl is-enabled --quiet anonsurfd 2>/dev/null; then
    echo -e "[${GRN}*${RST}] Boot :     ${GRN}ACTIVÉ${RST}"
  else echo -e "[${YLW}*${RST}] Boot :     ${YLW}DÉSACTIVÉ${RST}"; fi
  echo ""; do_myip
}

do_myip() {
  echo -e "[${GRN}*${RST}]${BLU} Vérification de l'IP publique...${RST}"
  local resp; resp=$(curl -s --max-time 10 https://check.torproject.org/api/ip 2>/dev/null)
  if [[ -n "$resp" ]]; then
    local is_tor; is_tor=$(echo "$resp" | grep -o '"IsTor":[a-z]*' | cut -d: -f2)
    local addr; addr=$(echo "$resp" | grep -o '"IP":"[^"]*"' | cut -d'"' -f4)
    if [[ "$is_tor" == "true" ]]; then
      echo -e "[${GRN}*${RST}] IP : ${GRN}$addr${RST} (via Tor)"
    else
      echo -e "[${YLW}!${RST}] IP : ${YLW}$addr${RST} (${RED}PAS via Tor${RST})"
    fi
  else echo -e "[${RED}!${RST}] Impossible de déterminer l'IP publique."; fi
}

case "${1:-help}" in
  start)        do_start ;;
  stop)         do_stop ;;
  restart)      do_restart ;;
  changeid)     do_changeid ;;
  status)       do_status ;;
  myip)         do_myip ;;
  enable-boot)  check_root; systemctl enable anonsurfd 2>/dev/null; echo -e "[${GRN}*${RST}] AnonSurf activé au boot." ;;
  disable-boot) check_root; systemctl disable anonsurfd 2>/dev/null; echo -e "[${GRN}*${RST}] AnonSurf désactivé au boot." ;;
  help)         show_help ;;
  *)            echo -e "[${RED}!${RST}] Option invalide : $1"; show_help; exit 1 ;;
esac
EOFCLI
  chmod +x /usr/bin/anonsurf

  success "AnonSurf installé. Usage : sudo anonsurf start|stop|status|myip"
}

install_anonsurf

# ═══════════════════════════════════════════════════════════════════════════════
#  15. PORT CONSOLE & DIVERS RÉSEAU
# ═══════════════════════════════════════════════════════════════════════════════
title "15. Console série & divers réseau"

apt_install "serial_misc" \
  cu minicom picocom screen setserial gtkterm \
  socat wakeonlan bridge-utils tftp-hpa tftpd-hpa

# ═══════════════════════════════════════════════════════════════════════════════
#  16. ADMINISTRATION À DISTANCE
# ═══════════════════════════════════════════════════════════════════════════════
title "16. Administration à distance"

apt_install "remote" \
  rdesktop freerdp2-x11 openssh-client sshfs pssh clusterssh tmux \
  remmina remmina-plugin-rdp remmina-plugin-vnc remmina-plugin-secret \
  smbclient sshpass

# ═══════════════════════════════════════════════════════════════════════════════
#  17. SAUVEGARDES
# ═══════════════════════════════════════════════════════════════════════════════
title "17. Sauvegardes"

apt_install "backup" \
  dirvish automysqlbackup bacula-client bacula-console dump \
  duplicity restic rsync rdiff-backup borgbackup rclone grsync zsync

# ═══════════════════════════════════════════════════════════════════════════════
#  18. FTP
# ═══════════════════════════════════════════════════════════════════════════════
title "18. FTP"

apt_install "ftp" \
  filezilla gftp lftp

# ═══════════════════════════════════════════════════════════════════════════════
#  19. VIRTUALISATION
# ═══════════════════════════════════════════════════════════════════════════════
title "19. Virtualisation"

apt_install "virtualization" \
  virt-manager qemu-system qemu-system-x86 qemu-utils \
  libvirt-clients libvirt-daemon libvirt-daemon-system \
  virtinst virt-viewer \
  lxc

# ─── VirtualBox (via dépôt Oracle) ───────────────────────────────────────────
install_virtualbox() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "virtualization" ]]; then return; fi
  info "Installation VirtualBox via dépôt Oracle..."
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation VirtualBox (Oracle repo)"
    return
  fi
  wget -qO- https://www.virtualbox.org/download/oracle_vbox_2016.asc \
    | gpg --yes --dearmor -o /usr/share/keyrings/oracle-virtualbox-2016.gpg 2>/dev/null || true
  echo "deb [arch=amd64 signed-by=/usr/share/keyrings/oracle-virtualbox-2016.gpg] \
https://download.virtualbox.org/virtualbox/debian ${DISTRO_CODENAME} contrib" \
    > /etc/apt/sources.list.d/virtualbox.list
  apt-get update -qq && apt-get install -y virtualbox-7.0 || warn "VirtualBox : installation échouée"
}

install_virtualbox

# ═══════════════════════════════════════════════════════════════════════════════
#  20. SYSTÈME DIVERS (Administration)
# ═══════════════════════════════════════════════════════════════════════════════
title "20. Divers système & Administration"

apt_install "sysadmin_misc" \
  xca krb5-config krb5-pkinit krb5-user \
  apache2-utils chrony python3-ldap3 \
  apparmor apparmor-profiles apparmor-utils

apt_install "db_clients" \
  mariadb-client postgresql-client

# ═══════════════════════════════════════════════════════════════════════════════
#  21. DEVOPS & CLOUD
# ═══════════════════════════════════════════════════════════════════════════════
title "21. DevOps & Cloud"

# Docker
apt_install "docker" \
  docker.io docker-compose containerd

# Ansible
apt_install "ansible" \
  ansible ansible-lint

# Outils DevOps dans les dépôts standard
apt_install "devops_std" \
  podman buildah

# ─── Outils DevOps via installation directe ─────────────────────────────────
install_devops_extras() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "devops" ]]; then return; fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation outils DevOps extras (kubectl, k9s, minikube, lazydocker)"
    return
  fi

  local ARCH; ARCH=$(dpkg --print-architecture)

  # kubectl
  if ! command -v kubectl &>/dev/null; then
    info "Installation kubectl..."
    curl -fsSL "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl" \
      -o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl || warn "kubectl : échec"
  fi

  # minikube
  if ! command -v minikube &>/dev/null; then
    info "Installation minikube..."
    curl -fsSLo /usr/local/bin/minikube \
      "https://storage.googleapis.com/minikube/releases/latest/minikube-linux-${ARCH}" \
      && chmod +x /usr/local/bin/minikube || warn "minikube : échec"
  fi

  # lazydocker
  if ! command -v lazydocker &>/dev/null; then
    info "Installation lazydocker..."
    local LD_VERSION
    LD_VERSION=$(curl -s https://api.github.com/repos/jesseduffield/lazydocker/releases/latest \
      | grep '"tag_name"' | cut -d'"' -f4 | tr -d 'v')
    curl -fsSL "https://github.com/jesseduffield/lazydocker/releases/latest/download/lazydocker_${LD_VERSION}_Linux_x86_64.tar.gz" \
      | tar xz -C /usr/local/bin lazydocker && chmod +x /usr/local/bin/lazydocker || warn "lazydocker : échec"
  fi

  success "DevOps extras installés."
}

install_devops_extras

# ═══════════════════════════════════════════════════════════════════════════════
#  22. SYSTÈMES DE FICHIERS
# ═══════════════════════════════════════════════════════════════════════════════
title "22. Systèmes de fichiers"

apt_install "filesystems" \
  cryptsetup cryptsetup-initramfs dmsetup mdadm lvm2 \
  dosfstools f2fs-tools nilfs-tools \
  btrfs-progs \
  hfsplus hfsprogs hfsutils \
  jfsutils \
  xfsdump xfsprogs \
  zfsutils-linux zfs-zed \
  exfatprogs fuse3 udftools \
  cifs-utils ntfs-3g wimtools \
  dislocker

# ═══════════════════════════════════════════════════════════════════════════════
#  23. SNAPSHOTS SYSTÈME
# ═══════════════════════════════════════════════════════════════════════════════
title "23. Snapshots système"

apt_install "snapshots" \
  snapper timeshift btrbk

# ═══════════════════════════════════════════════════════════════════════════════
#  24. OUTILS DIVERS / MISCELLANEOUS
# ═══════════════════════════════════════════════════════════════════════════════
title "24. Outils divers"

apt_install "misc" \
  progress pv less plocate dirmngr gpa gpg gnupg2 curl wget git \
  gpg-agent img2pdf mc strace ltrace tree vim cups hexedit file \
  psmisc htop lsof lzop p7zip-full pigz unp unar unrar-free unzip \
  zip bzip2 tar unrar zstd gtkhash keepassxc apg pwgen \
  cabextract btop jq yq yamllint simple-scan

# ═══════════════════════════════════════════════════════════════════════════════
#  25. GNS3 (réseau lab)
# ═══════════════════════════════════════════════════════════════════════════════
install_gns3() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "network" ]]; then return; fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation GNS3"
    return
  fi
  if $IS_UBUNTU; then
    info "Installation GNS3 via PPA..."
    add-apt-repository -y ppa:gns3/ppa 2>&1 | tee -a "$LOG_FILE" || true
    apt-get update -qq
    DEBIAN_FRONTEND=noninteractive apt-get install -y gns3-gui gns3-server dynamips vpcs || \
      warn "GNS3 : installation incomplète"
  else
    info "Installation GNS3 depuis les dépôts Debian..."
    DEBIAN_FRONTEND=noninteractive apt-get install -y gns3-gui gns3-server dynamips vpcs 2>&1 | tee -a "$LOG_FILE" || \
      warn "GNS3 : non disponible dans les dépôts Debian — installer via pip : pip3 install gns3-gui gns3-server"
  fi
}

install_gns3

# ═══════════════════════════════════════════════════════════════════════════════
#  26. POWERSHELL
# ═══════════════════════════════════════════════════════════════════════════════
install_powershell() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "misc" ]]; then return; fi
  if command -v pwsh &>/dev/null; then
    info "PowerShell déjà installé."; return
  fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation PowerShell"
    return
  fi

  local ARCH; ARCH=$(dpkg --print-architecture)
  if [[ "$ARCH" != "amd64" ]]; then
    warn "PowerShell : architecture $ARCH non supportée"; return
  fi

  info "Installation PowerShell via packages.microsoft.com..."
  curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --yes --dearmor -o /usr/share/keyrings/microsoft-prod.gpg 2>/dev/null || true

  local ms_codename="$DISTRO_CODENAME"
  if $IS_UBUNTU || [[ "$DISTRO_ID" == "pop" ]]; then
    local ubuntu_codename
    ubuntu_codename=$(. /etc/os-release && echo "${UBUNTU_CODENAME:-}")
    if [[ -n "$ubuntu_codename" ]]; then
      ms_codename="$ubuntu_codename"
    fi
    echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/ubuntu/${ms_codename}/prod ${ms_codename} main" \
      > /etc/apt/sources.list.d/microsoft-prod.list 2>/dev/null || true
  else
    echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/debian/${DISTRO_CODENAME}/prod ${DISTRO_CODENAME} main" \
      > /etc/apt/sources.list.d/microsoft-prod.list 2>/dev/null || true
  fi

  if apt-get update -qq && apt-get install -y powershell 2>&1 | tee -a "$LOG_FILE"; then
    success "PowerShell installé."
  else
    warn "PowerShell : dépôt Microsoft indisponible pour ${ms_codename} — installation via .deb..."
    local PS_VERSION
    PS_VERSION=$(curl -s https://api.github.com/repos/PowerShell/PowerShell/releases/latest \
      | grep '"tag_name"' | cut -d'"' -f4 | tr -d 'v')
    if [[ -n "$PS_VERSION" ]]; then
      local DEB_FILE="/tmp/powershell_${PS_VERSION}_amd64.deb"
      curl -fsSL "https://github.com/PowerShell/PowerShell/releases/download/v${PS_VERSION}/powershell_${PS_VERSION}-1.deb_amd64.deb" \
        -o "$DEB_FILE" && dpkg -i "$DEB_FILE" && apt-get install -f -y 2>&1 | tee -a "$LOG_FILE" \
        && rm -f "$DEB_FILE" \
        || warn "PowerShell : installation via .deb échouée — voir https://learn.microsoft.com/powershell/scripting/install/installing-powershell-on-linux"
    else
      warn "PowerShell : impossible de déterminer la dernière version"
    fi
  fi
}

install_powershell

# ═══════════════════════════════════════════════════════════════════════════════
#  27. OUTILS IA
# ═══════════════════════════════════════════════════════════════════════════════
title "27. Outils IA"

apt_install "ai_base" \
  python3-pip python3-venv python3-full nodejs npm

# ─── Ollama (LLM local) ─────────────────────────────────────────────────────
install_ollama() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "ai" ]]; then return; fi
  if command -v ollama &>/dev/null; then
    info "Ollama déjà installé."; return
  fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation Ollama"
    return
  fi

  info "Installation Ollama..."
  curl -fsSL https://ollama.com/install.sh | sh 2>&1 | tee -a "$LOG_FILE" || warn "Ollama : installation échouée"

  if command -v ollama &>/dev/null; then
    success "Ollama installé."
  fi
}

install_ollama

# ─── Claude Code (CLI Anthropic) ─────────────────────────────────────────────
install_claude_code() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "ai" ]]; then return; fi
  if command -v claude &>/dev/null; then
    info "Claude Code déjà installé."; return
  fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation Claude Code (npm)"
    return
  fi

  if ! command -v npm &>/dev/null; then
    warn "Claude Code : npm non disponible — installation impossible"
    return
  fi

  info "Installation Claude Code..."
  npm install -g @anthropic-ai/claude-code 2>&1 | tee -a "$LOG_FILE" || warn "Claude Code : installation échouée"

  if command -v claude &>/dev/null; then
    success "Claude Code installé."
  fi
}

install_claude_code

# ─── Open WebUI (interface web pour Ollama) ──────────────────────────────────
install_open_webui() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "ai" ]]; then return; fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Pull Docker open-webui"
    return
  fi

  if ! command -v docker &>/dev/null; then
    warn "Open WebUI : Docker non disponible — installation ignorée"
    return
  fi

  if docker image inspect ghcr.io/open-webui/open-webui:main &>/dev/null 2>&1; then
    info "Open WebUI : image Docker déjà présente."
    return
  fi

  info "Téléchargement de l'image Open WebUI..."
  docker pull ghcr.io/open-webui/open-webui:main 2>&1 | tee -a "$LOG_FILE" || warn "Open WebUI : pull échoué"
  success "Open WebUI prêt. Lancer avec : docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui ghcr.io/open-webui/open-webui:main"
}

install_open_webui

# ═══════════════════════════════════════════════════════════════════════════════
#  28. OSINT (Open Source Intelligence)
# ═══════════════════════════════════════════════════════════════════════════════
title "28. OSINT — Open Source Intelligence"

apt_install "osint_base" \
  libimage-exiftool-perl mat2 mediainfo sublist3r

# ─── Outils OSINT via pip ────────────────────────────────────────────────────
install_osint_pip() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "osint" ]]; then return; fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation outils OSINT via pip (sherlock, holehe, maigret, recon-ng, theHarvester, spiderfoot)"
    return
  fi

  if ! command -v pip3 &>/dev/null; then
    warn "OSINT pip : pip3 non disponible — installation ignorée"
    return
  fi

  local pip_tools=("sherlock-project" "holehe" "maigret" "recon-ng" "theHarvester" "spiderfoot")
  for tool in "${pip_tools[@]}"; do
    if pip3 show "$tool" &>/dev/null 2>&1; then
      skip "$tool déjà installé (pip)"
    else
      info "Installation $tool via pip..."
      pip3 install --break-system-packages "$tool" 2>&1 | tee -a "$LOG_FILE" || warn "$tool : installation pip échouée"
    fi
  done

  success "Outils OSINT pip installés."
}

install_osint_pip

# ─── Amass (énumération DNS / sous-domaines) ─────────────────────────────────
install_amass() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "osint" ]]; then return; fi
  if command -v amass &>/dev/null; then
    info "Amass déjà installé."; return
  fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation Amass"
    return
  fi

  local ARCH; ARCH=$(dpkg --print-architecture)
  info "Installation Amass..."
  local AMASS_VERSION
  AMASS_VERSION=$(curl -s https://api.github.com/repos/owasp-amass/amass/releases/latest \
    | grep '"tag_name"' | cut -d'"' -f4 | tr -d 'v')
  if [[ -n "$AMASS_VERSION" ]]; then
    local amass_arch="amd64"
    [[ "$ARCH" == "arm64" ]] && amass_arch="arm64"
    curl -fsSL "https://github.com/owasp-amass/amass/releases/download/v${AMASS_VERSION}/amass_Linux_${amass_arch}.zip" \
      -o /tmp/amass.zip \
      && unzip -o /tmp/amass.zip -d /tmp/amass_extract \
      && install -m 755 /tmp/amass_extract/amass_Linux_${amass_arch}/amass /usr/local/bin/amass \
      && rm -rf /tmp/amass.zip /tmp/amass_extract \
      || warn "Amass : installation échouée"
  else
    warn "Amass : impossible de déterminer la dernière version"
  fi

  if command -v amass &>/dev/null; then
    success "Amass installé."
  fi
}

install_amass

# ─── PhoneInfoga (OSINT téléphone) ───────────────────────────────────────────
install_phoneinfoga() {
  if [[ -n "$SECTION_FILTER" ]] && [[ "$SECTION_FILTER" != "osint" ]]; then return; fi
  if command -v phoneinfoga &>/dev/null; then
    info "PhoneInfoga déjà installé."; return
  fi
  if $DRY_RUN; then
    echo "[DRY-RUN] Installation PhoneInfoga"
    return
  fi

  info "Installation PhoneInfoga..."
  curl -fsSL "https://raw.githubusercontent.com/sundowndev/phoneinfoga/master/support/scripts/install" | bash 2>&1 | tee -a "$LOG_FILE" \
    && mv ./phoneinfoga /usr/local/bin/phoneinfoga 2>/dev/null \
    || warn "PhoneInfoga : installation échouée"

  if command -v phoneinfoga &>/dev/null; then
    success "PhoneInfoga installé."
  fi
}

install_phoneinfoga

# ═══════════════════════════════════════════════════════════════════════════════
#  RÉSUMÉ FINAL
# ═══════════════════════════════════════════════════════════════════════════════
title "Installation terminée"
echo -e "${GRN}${BOLD}"
echo "  ╔══════════════════════════════════════════════════════╗"
echo "  ║       Tech Tools : Installation terminée !          ║"
echo "  ╚══════════════════════════════════════════════════════╝"
echo -e "${RST}"
info "Log complet : $LOG_FILE"
warn "Certains paquets spécifiques (exegol, etc.) n'existent"
warn "pas dans les dépôts Ubuntu et ont été ignorés intentionnellement."
warn "Pour Exegol, consulter : https://exegol.readthedocs.io/en/latest/getting-started/install.html"

echo ""
echo -e "${BLU}Outils nécessitant une action manuelle supplémentaire :${RST}"
echo "  • VeraCrypt   → https://www.veracrypt.fr/en/Downloads.html"
echo "  • Exegol      → https://exegol.readthedocs.io"
echo "  • Azure CLI   → https://learn.microsoft.com/cli/azure/install-azure-cli-linux"
echo "  • Terraform   → https://developer.hashicorp.com/terraform/downloads"
echo "  • Helm        → https://helm.sh/docs/intro/install/"
echo "  • Vagrant     → https://developer.hashicorp.com/vagrant/downloads"
echo "  • Packer      → https://developer.hashicorp.com/packer/downloads"
echo "  • AWS CLI     → https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html"
echo "  • SSLyze      → pip3 install sslyze"
echo "  • LazyGit     → https://github.com/jesseduffield/lazygit#installation"
echo "  • VSCodium    → https://vscodium.com/#install"
echo "  • Cursor      → https://www.cursor.com/downloads"
echo "  • LM Studio   → https://lmstudio.ai/"
echo "  • Maltego     → https://www.maltego.com/downloads/"
echo "  • MalTrail   → https://github.com/stamparm/maltrail (git clone)"
echo ""
if command -v ollama &>/dev/null || command -v claude &>/dev/null; then
  echo -e "${BLU}Outils IA :${RST}"
  command -v ollama &>/dev/null && echo "  • ollama run llama3         → Lancer un modèle local"
  command -v ollama &>/dev/null && echo "  • ollama list               → Lister les modèles installés"
  command -v claude &>/dev/null && echo "  • claude                    → Lancer Claude Code (CLI)"
  if docker image inspect ghcr.io/open-webui/open-webui:main &>/dev/null 2>&1; then
    echo "  • Open WebUI               → docker start open-webui (port 3000)"
  fi
  echo ""
fi
if command -v sherlock &>/dev/null || command -v holehe &>/dev/null || command -v amass &>/dev/null; then
  echo -e "${BLU}OSINT :${RST}"
  command -v sherlock &>/dev/null    && echo "  • sherlock <username>        → Recherche de comptes sur les réseaux sociaux"
  command -v holehe &>/dev/null      && echo "  • holehe <email>             → Vérifier sur quels sites un email est inscrit"
  command -v maigret &>/dev/null     && echo "  • maigret <username>         → Profiling avancé de comptes"
  command -v amass &>/dev/null       && echo "  • amass enum -d <domain>     → Énumération DNS / sous-domaines"
  command -v phoneinfoga &>/dev/null && echo "  • phoneinfoga scan -n <num>  → OSINT sur numéro de téléphone"
  command -v exiftool &>/dev/null    && echo "  • exiftool <fichier>         → Extraction de métadonnées"
  command -v mat2 &>/dev/null        && echo "  • mat2 <fichier>             → Nettoyage de métadonnées"
  command -v theharvester &>/dev/null && echo "  • theHarvester -d <domain>   → Collecte emails/sous-domaines"
  echo ""
fi
if command -v anonsurf &>/dev/null; then
  echo -e "${BLU}Anonymisation (Tor & AnonSurf) :${RST}"
  echo "  • sudo anonsurf start    → Démarrer le proxy Tor transparent"
  echo "  • sudo anonsurf stop     → Arrêter et restaurer le trafic normal"
  echo "  • sudo anonsurf status   → Vérifier l'état"
  echo "  • sudo anonsurf myip     → Vérifier l'IP publique"
  echo ""
fi