#!/usr/bin/env bash
# Fetch the Metasploitable2 disk image with no operator interaction.
#
# Defaults to the SourceForge public mirror — the canonical
# freely-redistributable copy of Metasploitable2 (Rapid7's own
# download is registration-walled but the same VMDK is on
# SourceForge, downloaded ~2M times). HTTPS protects the transport.
#
# Idempotent: if the qcow2 is already on disk we do nothing.
#
# Inputs (env, all optional):
#   IMAGE_URL    — override the default mirror URL
#   IMAGE_SHA256 — verify against this hash. If unset and a sha256
#                  has been recorded by a prior successful fetch
#                  ($OUT_DIR/metasploitable2.qcow2.sha256), use that.
#                  If neither is available, do TOFU (trust on first
#                  use): record the hash of what was downloaded so
#                  subsequent runs verify against it.
#   OUT_DIR      — where to drop the qcow2 (default vm/images/)
#
# Outputs:
#   $OUT_DIR/metasploitable2.qcow2          — the disk image
#   $OUT_DIR/metasploitable2.qcow2.sha256   — recorded archive hash

set -euo pipefail

# SourceForge public mirror. Direct-download URL — no auth, no
# registration. /download 302s to a regional mirror.
DEFAULT_IMAGE_URL='https://downloads.sourceforge.net/project/metasploitable/Metasploitable2/metasploitable-linux-2.0.0.zip'

IMAGE_URL="${IMAGE_URL:-$DEFAULT_IMAGE_URL}"
IMAGE_SHA256="${IMAGE_SHA256:-}"
OUT_DIR="${OUT_DIR:-$(cd "$(dirname "$0")/../vm/images" 2>/dev/null && pwd)}"
WORK_DIR="${WORK_DIR:-/tmp/cis490-metasploitable-fetch}"

log() { printf '[fetch-metasploitable2] %s\n' "$*" >&2; }
die() { log "FATAL: $*"; exit 1; }

mkdir -p "$OUT_DIR" "$WORK_DIR"

# Short-circuit if the qcow2 is already on disk.
if [[ -f "$OUT_DIR/metasploitable2.qcow2" ]]; then
    log "$OUT_DIR/metasploitable2.qcow2 already present; nothing to do"
    exit 0
fi

# Use the recorded sha256 from a prior successful fetch if present
# and the env var didn't override it. This pins TOFU across runs
# so a tampered re-download fails noisily.
SHA_FILE="$OUT_DIR/metasploitable2.qcow2.sha256"
if [[ -z "$IMAGE_SHA256" && -f "$SHA_FILE" ]]; then
    IMAGE_SHA256="$(awk '{print $1}' "$SHA_FILE")"
    log "using pinned sha256 from $SHA_FILE: $IMAGE_SHA256"
fi

ARCHIVE="$WORK_DIR/$(basename "$IMAGE_URL")"
log "downloading $IMAGE_URL → $ARCHIVE"
if [[ -f "$ARCHIVE" ]]; then
    log "archive already present in work dir; skipping download"
else
    # -L follows SourceForge's redirect to the actual mirror.
    curl -fL --retry 3 --retry-delay 5 -o "$ARCHIVE.partial" "$IMAGE_URL"
    mv "$ARCHIVE.partial" "$ARCHIVE"
fi

ACTUAL="$(sha256sum "$ARCHIVE" | awk '{print $1}')"
if [[ -n "$IMAGE_SHA256" ]]; then
    if [[ "$ACTUAL" != "$IMAGE_SHA256" ]]; then
        die "sha256 mismatch: expected $IMAGE_SHA256, got $ACTUAL"
    fi
    log "sha256 ok"
else
    log "no sha256 supplied — first-run TOFU; pinning $ACTUAL for future runs"
fi
# Always (re)record so future runs verify against the working hash.
echo "$ACTUAL  $(basename "$ARCHIVE")" > "$SHA_FILE"

# Extract — handle either zip or 7z, since various mirrors choose one
# or the other.
case "$ARCHIVE" in
    *.zip) ( cd "$WORK_DIR" && unzip -o "$ARCHIVE" ) ;;
    *.7z|*.7zip) command -v 7z >/dev/null || die "7z not installed"; \
                 ( cd "$WORK_DIR" && 7z x -y "$ARCHIVE" ) ;;
    *) die "unsupported archive type: $ARCHIVE" ;;
esac

VMDK="$(find "$WORK_DIR" -name 'Metasploitable*.vmdk' -print -quit)"
[[ -n "$VMDK" ]] || die "no Metasploitable*.vmdk in extracted archive"

log "converting $VMDK → qcow2"
command -v qemu-img >/dev/null || die "qemu-img required (apt install qemu-utils)"
qemu-img convert -O qcow2 "$VMDK" "$OUT_DIR/metasploitable2.qcow2"

# Best-effort cleanup of the work dir — keeps lab-host disk clean.
rm -rf "$WORK_DIR"

log "done: $OUT_DIR/metasploitable2.qcow2"
log "Tier-3 ready when msfrpcd is up. See scripts/install-msfrpcd.sh."
