#!/usr/bin/env sh

set -u

F4L_VERSION="4.1.0"
LOGFILE="/tmp/forensic4linux-toolkit.log"
MISSING=""
DRYRUN=0
WITH_LIME=0
SUDO=""
PKGMGR=""
ID=""
ID_LIKE=""

GREEN=""
YELLOW=""
CYAN=""
RED=""
NC=""

if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
  GREEN="$(tput setaf 2)"
  YELLOW="$(tput setaf 3)"
  CYAN="$(tput setaf 6)"
  RED="$(tput setaf 1)"
  NC="$(tput sgr0)"
fi

say()  { printf '%b[+]%b %s\n' "$GREEN" "$NC" "$*"; }
info() { printf '%b[*]%b %s\n' "$CYAN" "$NC" "$*"; }
warn() { printf '%b[!]%b %s\n' "$YELLOW" "$NC" "$*"; }
die()  { printf '%b[x]%b %s\n' "$RED" "$NC" "$*" >&2; exit 1; }

have() {
  command -v "$1" >/dev/null 2>&1 \
    || [ -x "/usr/sbin/$1" ] || [ -x "/sbin/$1" ] \
    || [ -x "/usr/local/bin/$1" ] || [ -x "/usr/local/sbin/$1" ]
}

banner() {
  printf '%b\n' "$CYAN"
  printf '  ___________________________________________\n'
  printf '  |  forensic4linux.com  |  FORENSICS KIT     |\n'
  printf '  |  Toolbox installer   |  v%s            |\n' "$F4L_VERSION"
  printf '  ___________________________________________\n'
  printf '%b\n' "$NC"
}

usage() {
  banner
  echo "  install with:"
  echo "    curl -sS https://forensic4linux.com/download/toolkit | sh"
  echo "    curl -sS https://forensic4linux.com/download/toolkit | sudo sh"
  echo ""
  echo "  options:"
  echo "    --dry-run    show what would be installed, then exit"
  echo "    --with-lime  also build the LiME memory capture module"
  echo "    --help       this message"
}

detect_distro() {
  if [ -f /etc/os-release ]; then
    ID="$(sed -n 's/^ID=//p' /etc/os-release | tr -d '"')"
    ID_LIKE="$(sed -n 's/^ID_LIKE=//p' /etc/os-release | tr -d '"')"
  fi
  case "$ID $ID_LIKE" in
    *debian*|*ubuntu*) PKGMGR="apt" ;;
    *fedora*|*rhel*|*centos*|*rocky*|*alma*) PKGMGR="dnf" ;;
    *arch*) PKGMGR="pacman" ;;
    *suse*|*opensuse*) PKGMGR="zypper" ;;
    *alpine*) PKGMGR="apk" ;;
  esac
  if [ "$PKGMGR" = "dnf" ] && ! command -v dnf >/dev/null 2>&1 && command -v yum >/dev/null 2>&1; then
    PKGMGR="yum"
  fi
}

pkg_name() {
  case "$PKGMGR:$1" in
    apt:exiftool)     echo "libimage-exiftool-perl" ;;
    apt:7z)           echo "p7zip-full" ;;
    apt:ewfacquire)   echo "libewf-utils" ;;
    apt:ddrescue)     echo "gddrescue" ;;
    apt:bulk-extractor) echo "bulk-extractor" ;;
    dnf:exiftool)     echo "perl-Image-ExifTool" ;;
    dnf:7z)           echo "p7zip" ;;
    dnf:ewfacquire)   echo "libewf" ;;
    dnf:ddrescue)     echo "ddrescue" ;;
    dnf:bulk-extractor) echo "bulk_extractor" ;;
    yum:exiftool)     echo "perl-Image-ExifTool" ;;
    yum:7z)           echo "p7zip" ;;
    yum:ewfacquire)   echo "libewf" ;;
    yum:ddrescue)     echo "ddrescue" ;;
    yum:bulk-extractor) echo "bulk_extractor" ;;
    apk:7z)           echo "p7zip" ;;
    apk:ewfacquire)   echo "libewf" ;;
    apk:ddrescue)     echo "ddrescue" ;;
    *)                echo "$1" ;;
  esac
}

install_tool() {
  CMD_NAME="$1"
  PKG_BASE="$2"
  if have "$CMD_NAME"; then
    say "already present: $CMD_NAME"
    return 0
  fi
  PKG_NAME="$(pkg_name "$PKG_BASE")"
  info "downloading & installing $CMD_NAME ($PKG_NAME)"
  case "$PKGMGR" in
    apt)     $SUDO apt-get install -y "$PKG_NAME" >>"$LOGFILE" 2>&1 ;;
    dnf)     $SUDO dnf install -y "$PKG_NAME" >>"$LOGFILE" 2>&1 ;;
    yum)     $SUDO yum install -y "$PKG_NAME" >>"$LOGFILE" 2>&1 ;;
    pacman)  $SUDO pacman -S --noconfirm --needed "$PKG_NAME" >>"$LOGFILE" 2>&1 ;;
    zypper)  $SUDO zypper --non-interactive install "$PKG_NAME" >>"$LOGFILE" 2>&1 ;;
    apk)     $SUDO apk add --no-cache "$PKG_NAME" >>"$LOGFILE" 2>&1 ;;
    *)
      warn "unsupported package manager - install $PKG_NAME manually"
      MISSING="$MISSING $CMD_NAME"
      return 1
      ;;
  esac
  if have "$CMD_NAME"; then
    say "installed: $CMD_NAME"
    return 0
  fi
  warn "not installed: $CMD_NAME ($PKG_NAME) - see log, or add manually"
  MISSING="$MISSING $CMD_NAME"
  return 1
}

install_volatility() {
  if have vol3 || have vol; then
    say "already present: volatility"
    return 0
  fi
  info "downloading & installing volatility3 from PyPI"
  if python3 -m pip install --user volatility3 >>"$LOGFILE" 2>&1; then
    say "installed: volatility3 (user site)"
  elif python3 -m pip install volatility3 >>"$LOGFILE" 2>&1; then
    say "installed: volatility3"
  elif python3 -m pip install --break-system-packages volatility3 >>"$LOGFILE" 2>&1; then
    say "installed: volatility3 (system, break-system-packages)"
  else
    warn "could not install volatility3 - try: pip install volatility3"
    MISSING="$MISSING volatility3"
  fi
}

install_lime() {
  info "building LiME memory capture module for kernel $(uname -r)"
  case "$PKGMGR" in
    apt) $SUDO apt-get install -y build-essential git "linux-headers-$(uname -r)" >>"$LOGFILE" 2>&1 ;;
    dnf|yum) $SUDO dnf install -y gcc make git kernel-devel >>"$LOGFILE" 2>&1 ;;
  esac
  if [ -d /opt/lime ]; then rm -rf /opt/lime; fi
  git clone --depth 1 https://github.com/504ensicsLabs/lime /opt/lime >>"$LOGFILE" 2>&1
  (cd /opt/lime/src && make) >>"$LOGFILE" 2>&1
  if [ -d /opt/lime/src ] && ls /opt/lime/src/lime-*.ko >/dev/null 2>&1; then
    mkdir -p /opt/lime/modules
    cp /opt/lime/src/lime-*.ko /opt/lime/modules/ 2>/dev/null
    say "LiME built -> /opt/lime/modules/"
  else
    warn "LiME build failed - install the matching kernel headers, then retry"
    MISSING="$MISSING lime"
  fi
}

for ARG in "$@"; do
  case "$ARG" in
    --dry-run) DRYRUN=1 ;;
    --with-lime) WITH_LIME=1 ;;
    --help|-h) usage; exit 0 ;;
  esac
done

banner
detect_distro

if [ -z "$PKGMGR" ]; then
  die "could not detect your package manager (apt/dnf/pacman/zypper/apk). Install the tools manually."
fi

info "detected package manager: $PKGMGR"

if [ "$(id -u)" -ne 0 ]; then
  if command -v sudo >/dev/null 2>&1; then
    SUDO="sudo"
    info "not running as root - using sudo for package commands (password may be asked)"
  else
    die "root privileges required. Re-run with: curl -sS https://forensic4linux.com/download/toolkit | sudo sh"
  fi
else
  SUDO=""
fi

echo ""
info "this script will install the following forensic tools:"
cat <<'EOF'
  The Sleuth Kit (fls, icat, istat, mmls, fsstat)
  Autopsy (GUI front-end for The Sleuth Kit)
  dcfldd (imaging with on-the-fly hashing)
  testdisk / photorec (partition recovery & media carving)
  foremost (signature-based file carving)
  scalpel (fast config-driven file carving)
  bulk_extractor (bulk artifact extraction)
  extundelete (deleted file recovery on ext3/ext4)
  ddrescue (robust drive imaging)
  debugfs / e2fsprogs (ext filesystem internals)
  strings / binutils (text extraction from binaries)
  ripgrep (fast grep for log & image searching)
  libewf tools (E01/EWF evidence format)
  7z / unzip (archive handling)
  exiftool (metadata extraction)
  smartctl / hdparm (drive health & info)
  volatility3 (memory forensics, via pip)
EOF
echo ""

if [ "$DRYRUN" = "1" ]; then
  info "dry run - nothing was installed. Run without --dry-run to install."
  exit 0
fi

info "all output is logged to: $LOGFILE"
: > "$LOGFILE"

if [ "$PKGMGR" = "apt" ]; then
  info "updating package lists..."
  $SUDO apt-get -qq update >>"$LOGFILE" 2>&1
fi

install_tool fls           sleuthkit
install_tool autopsy       autopsy
install_tool dcfldd        dcfldd
install_tool testdisk      testdisk
install_tool foremost      foremost
install_tool scalpel       scalpel
install_tool bulk_extractor bulk-extractor
install_tool extundelete   extundelete
install_tool ddrescue      ddrescue
install_tool debugfs       e2fsprogs
install_tool strings       binutils
install_tool rg            ripgrep
install_tool ewfacquire    ewfacquire
install_tool 7z            7z
install_tool unzip         unzip
install_tool exiftool      exiftool
install_tool smartctl      smartmontools
install_tool hdparm        hdparm

install_volatility

if [ "$WITH_LIME" = "1" ]; then
  install_lime
fi

echo ""
info "============================================"
info "installation finished"
info "============================================"
say "log file: $LOGFILE"
if [ -n "$MISSING" ]; then
  warn "the following could not be installed automatically:$MISSING"
  warn "check the log, then install them manually with your package manager."
fi
if have fls; then
  say "try it:  fls -r /evidence/image.dd"
fi
if have vol3 || have vol; then
  say "try it:  vol3 -f /evidence/ram.lime linux.pslist"
fi
if command -v python3 >/dev/null 2>&1; then
  warn "if pip installed volatility3 to ~/.local/bin, add it to PATH:"
  warn "export PATH=\"\$HOME/.local/bin:\$PATH\""
fi
echo ""
echo "forensic4linux.com - keep your evidence safe, analyze images not originals."
