#!/bin/bash
#
# jetbackup5-ssh-patch.sh
# Detects the installed JetBackup 5 version/tier ONCE and applies the
# matching official SSH.inc patch:
#   - 5.4.x  on ALPHA/EDGE   -> patch id=452
#   - 5.3.19 on RELEASE/RC   -> patch id=451
#
# Security hardening vs. the original one-liners:
#   * Runs with `set -u -o pipefail` and a restrictive umask
#   * Requires root (the target file is root-owned)
#   * Temp dir is mode 0700 (mktemp -d default) and removed on exit via trap
#   * Download forced over HTTPS with certificate verification
#   * Archive entry is extracted to stdout only (-O), so a malicious
#     archive cannot perform path traversal writes
#   * Sanity-checks the extracted file looks like PHP source before install
#   * Timestamped backup of the original file, perms/owner preserved
#   * Patch installed atomically via mv onto the same filesystem

set -u -o pipefail
umask 077

TARGET="/usr/local/jetapps/var/lib/jetbackup5/Core/Destination/SSH/SSH.inc"

log()  { printf '%s\n' "$*"; }
fail() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }

# --- Preconditions -----------------------------------------------------------

[ "$(id -u)" -eq 0 ] || fail "This script must be run as root."

BIN="$(command -v jetbackup5 2>/dev/null || true)"
[ -n "$BIN" ] || BIN="/usr/local/jetapps/usr/bin/jetbackup5"
[ -x "$BIN" ]   || fail "JetBackup 5 CLI not found. Patch not applied."
[ -f "$TARGET" ] || fail "Target file not found: $TARGET. JetBackup 5 may not be fully installed. Patch not applied."

# --- Detect version and tier (once) ------------------------------------------

OUT="$("$BIN" --version 2>&1)"
JBV="$(printf '%s\n' "$OUT"  | sed -nE 's/.*Base[[:space:]]+([0-9]+(\.[0-9]+){2,3}).*/\1/p')"
TIER="$(printf '%s\n' "$OUT" | sed -nE 's/.*Current Tier[[:space:]]+([A-Z]+).*/\1/p')"

log "Detected JetBackup version: ${JBV:-unknown}, tier: ${TIER:-unknown}"

case "${JBV}:${TIER}" in
    5.4.*:ALPHA|5.4.*:EDGE)
        URL="https://repo.jetlicense.com/patches/jetbackup5/jb5-ssh-60-patch-v5.4.tar"
        ARCHIVE_NAME="jb5-ssh-60-patch-v5.4.tar"
        ;;
    5.3.19*:RELEASE|5.3.19*:RC|5.3.19*:STABLE)
        URL="https://repo.jetlicense.com/patches/jetbackup5/jb5-ssh-60-patch-v5.3.19.tar"
        ARCHIVE_NAME="jb5-ssh-60-patch-v5.3.19.tar"
        ;;
    *)
        fail "Unsupported JetBackup version/tier: ${JBV:-unknown} ${TIER:-unknown}. This patch only supports v5.4.x on ALPHA/EDGE or v5.3.19 on RELEASE/RC."
        ;;
esac

log "Applying JetBackup $JBV ($TIER) SSH patch..."

# --- Secure temp workspace with guaranteed cleanup ----------------------------

TMP="$(mktemp -d)" || fail "Could not create temporary directory."
trap 'rm -rf -- "$TMP"' EXIT INT TERM

ARCHIVE="$TMP/$ARCHIVE_NAME"

# --- Download (HTTPS only, certs verified) ------------------------------------

wget --https-only --secure-protocol=auto -q -O "$ARCHIVE" "$URL" \
    || fail "Patch download failed. Patch not applied."
[ -s "$ARCHIVE" ] || fail "Downloaded archive is empty. Patch not applied."

# --- Validate and extract (stdout-only; no path traversal possible) -----------

FILE="$(tar -tf "$ARCHIVE" 2>/dev/null | grep -E '(^|/)SSH\.inc$' | head -n1)"
[ -n "$FILE" ] || fail "SSH.inc not found inside the archive. Patch not applied."

tar -xf "$ARCHIVE" -O -- "$FILE" > "$TMP/SSH.inc.new" \
    || fail "Archive extraction failed. Patch not applied."
[ -s "$TMP/SSH.inc.new" ] || fail "Extracted SSH.inc is empty. Patch not applied."

# Basic sanity check that this is PHP source, not an error page or junk
head -c 64 "$TMP/SSH.inc.new" | grep -q '<?php' \
    || fail "Extracted file does not look like a PHP source file. Patch not applied."

# --- Backup and atomic install -------------------------------------------------

BACKUP="$TARGET.bak.$(date +%F-%H%M%S)"
cp -a -- "$TARGET" "$BACKUP" || fail "Could not create backup. Patch not applied."

# Match the original file's permissions and ownership, then replace atomically
chmod --reference="$TARGET" "$TMP/SSH.inc.new"
chown --reference="$TARGET" "$TMP/SSH.inc.new"

# Stage on the same filesystem so mv is atomic
STAGE="$(dirname -- "$TARGET")/.SSH.inc.new.$$"
cp -f -- "$TMP/SSH.inc.new" "$STAGE" || fail "Could not stage patch file. Patch not applied."
mv -f -- "$STAGE" "$TARGET"          || { rm -f -- "$STAGE"; fail "Could not install patch file. Patch not applied."; }

log "Patch applied successfully for JetBackup $JBV on $TIER."
log "Backup of the original file saved at: $BACKUP"
