#!/usr/bin/env bash
set -euo pipefail

# Script Name: crack
# Description: Hash cracking helper (john/hashcat wrapper)
# Usage: crack <hashfile>              # Auto-detect and crack
#        crack <hashfile> -w wordlist  # Specify wordlist
#        crack <hashfile> -m md5       # Specify hash type
#        crack identify <hash>         # Identify hash type

VERSION="1.0.0"

# Colors
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly MAGENTA='\033[0;35m'
readonly BOLD='\033[1m'
readonly NC='\033[0m'

show_help() {
  echo -e "${BOLD}crack${NC} - Hash Cracking Helper v${VERSION}"
  echo
  echo -e "${BOLD}USAGE:${NC}"
  echo "  crack <hashfile> [OPTIONS]"
  echo "  crack identify <hash>"
  echo
  echo -e "${BOLD}COMMANDS:${NC}"
  echo -e "  ${CYAN}crack <file>${NC}         Crack hashes in file"
  echo -e "  ${CYAN}identify <hash>${NC}      Identify hash type"
  echo -e "  ${CYAN}show <file>${NC}          Show cracked passwords"
  echo
  echo -e "${BOLD}OPTIONS:${NC}"
  echo -e "  ${CYAN}-w, --wordlist FILE${NC}  Specify wordlist"
  echo -e "  ${CYAN}-m, --mode TYPE${NC}      Hash type (md5, sha1, sha256, ntlm, etc.)"
  echo -e "  ${CYAN}-r, --rules${NC}          Apply John rules"
  echo -e "  ${CYAN}-f, --format${NC}         John format string"
  echo -e "  ${CYAN}-h, --help${NC}           Show this help"
  echo
  echo -e "${BOLD}EXAMPLES:${NC}"
  echo "  crack hashes.txt                    # Auto crack with default wordlist"
  echo "  crack hashes.txt -w rockyou.txt     # Use specific wordlist"
  echo "  crack hashes.txt -m md5             # Specify MD5 hashes"
  echo "  crack identify 5f4dcc3b5aa765d61d8327deb882cf99"
  echo "  crack show hashes.txt               # Show cracked results"
  echo
  echo -e "${BOLD}COMMON HASH TYPES:${NC}"
  echo "  md5, sha1, sha256, sha512"
  echo "  ntlm, mssql, mysql"
  echo "  bcrypt, des, raw-md5"
  echo
  echo -e "${BOLD}INSTALLED TOOLS:${NC}"
  command -v john &>/dev/null && echo -e "  ${GREEN}✓${NC} john (John the Ripper)" || echo -e "  ${RED}✗${NC} john (install: sudo apt install john)"
  command -v hashcat &>/dev/null && echo -e "  ${GREEN}✓${NC} hashcat" || echo -e "  ${RED}✗${NC} hashcat (install: sudo apt install hashcat)"
  command -v hashid &>/dev/null && echo -e "  ${GREEN}✓${NC} hashid (hash identifier)" || echo -e "  ${RED}✗${NC} hashid (install: pip install hashid)"
}

# Detect available tools
get_cracker() {
  if command -v john &>/dev/null; then
    echo "john"
  elif command -v hashcat &>/dev/null; then
    echo "hashcat"
  else
    echo -e "${RED}Error:${NC} No hash cracker found" >&2
    echo "Install one: sudo apt install john hashcat" >&2
    exit 1
  fi
}

# Identify hash type
identify_hash() {
  local hash="$1"

  echo -e "${CYAN}[*]${NC} Identifying hash: ${BOLD}$hash${NC}"
  echo

  if command -v hashid &>/dev/null; then
    hashid "$hash"
  else
    # Manual identification based on length
    local len=${#hash}

    echo -e "${YELLOW}Hash Identification:${NC}"
    case "$len" in
      32)
        echo "  Possible: MD5, NTLM"
        echo "  John format: --format=raw-md5 or --format=nt"
        echo "  Hashcat mode: -m 0 (MD5) or -m 1000 (NTLM)"
        ;;
      40)
        echo "  Possible: SHA1"
        echo "  John format: --format=raw-sha1"
        echo "  Hashcat mode: -m 100"
        ;;
      64)
        echo "  Possible: SHA256, SHA3-256"
        echo "  John format: --format=raw-sha256"
        echo "  Hashcat mode: -m 1400"
        ;;
      128)
        echo "  Possible: SHA512"
        echo "  John format: --format=raw-sha512"
        echo "  Hashcat mode: -m 1700"
        ;;
      60)
        if [[ "$hash" =~ ^\$2[ayb]\$ ]]; then
          echo "  Identified: bcrypt"
          echo "  John format: --format=bcrypt"
          echo "  Hashcat mode: -m 3200"
        fi
        ;;
      *)
        echo "  Unknown hash type (length: $len)"
        echo "  Try: hashid '$hash'"
        ;;
    esac
  fi
}

# Find common wordlists
find_wordlist() {
  local wordlists=(
    "/usr/share/wordlists/rockyou.txt"
    "/usr/share/wordlists/rockyou.txt.gz"
    "/usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000000.txt"
    "/usr/share/dict/words"
  )

  for wordlist in "${wordlists[@]}"; do
    if [[ -f "$wordlist" ]]; then
      echo "$wordlist"
      return 0
    fi
  done

  echo ""
}

# Crack with John the Ripper
crack_john() {
  local hashfile="$1"
  local format="${2:-}"
  local wordlist="${3:-}"
  local rules="${4:-false}"

  echo -e "${CYAN}[*]${NC} Using John the Ripper"
  echo -e "${CYAN}[*]${NC} Hash file: $hashfile"

  local john_args=""

  if [[ -n "$format" ]]; then
    john_args="$john_args --format=$format"
    echo -e "${CYAN}[*]${NC} Format: $format"
  fi

  if [[ -n "$wordlist" ]]; then
    if [[ "$wordlist" == *.gz ]]; then
      echo -e "${CYAN}[*]${NC} Wordlist: $wordlist (gzipped)"
      john_args="$john_args --wordlist=<(zcat $wordlist)"
    else
      echo -e "${CYAN}[*]${NC} Wordlist: $wordlist"
      john_args="$john_args --wordlist=$wordlist"
    fi
  else
    auto_wordlist=$(find_wordlist)
    if [[ -n "$auto_wordlist" ]]; then
      echo -e "${CYAN}[*]${NC} Using default wordlist: $auto_wordlist"
      john_args="$john_args --wordlist=$auto_wordlist"
    fi
  fi

  if [[ "$rules" == "true" ]]; then
    john_args="$john_args --rules"
    echo -e "${CYAN}[*]${NC} Rules: enabled"
  fi

  echo
  echo -e "${GREEN}[*]${NC} Starting crack..."
  echo

  john $john_args "$hashfile"
}

# Show cracked passwords
show_cracked() {
  local hashfile="$1"

  echo -e "${CYAN}[*]${NC} Cracked passwords for: ${BOLD}$hashfile${NC}"
  echo

  if command -v john &>/dev/null; then
    john --show "$hashfile"
  else
    echo -e "${RED}Error:${NC} John not available"
    exit 1
  fi
}

# Parse arguments
if [[ $# -eq 0 ]] || [[ "$1" =~ ^(-h|--help|help)$ ]]; then
  show_help
  exit 0
fi

command="$1"
shift

case "$command" in
  identify|id)
    if [[ $# -lt 1 ]]; then
      echo -e "${RED}Error:${NC} Usage: crack identify <hash>"
      exit 1
    fi
    identify_hash "$1"
    ;;
  show)
    if [[ $# -lt 1 ]]; then
      echo -e "${RED}Error:${NC} Usage: crack show <hashfile>"
      exit 1
    fi
    show_cracked "$1"
    ;;
  *)
    # Assume first arg is hashfile
    hashfile="$command"

    if [[ ! -f "$hashfile" ]]; then
      echo -e "${RED}Error:${NC} Hash file not found: $hashfile"
      exit 1
    fi

    # Parse crack options
    format=""
    wordlist=""
    rules=false

    while [[ $# -gt 0 ]]; do
      case $1 in
        -w|--wordlist)
          wordlist="$2"
          shift 2
          ;;
        -m|--mode|-f|--format)
          format="$2"
          shift 2
          ;;
        -r|--rules)
          rules=true
          shift
          ;;
        *)
          echo -e "${RED}Error:${NC} Unknown option: $1"
          exit 1
          ;;
      esac
    done

    cracker=$(get_cracker)

    case "$cracker" in
      john)
        crack_john "$hashfile" "$format" "$wordlist" "$rules"
        ;;
      hashcat)
        echo -e "${YELLOW}⚠${NC} Hashcat support not yet implemented"
        echo "Use John the Ripper or implement hashcat wrapper"
        exit 1
        ;;
    esac
    ;;
esac
