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

# Scarica un archivio tar.gz di Limristem eMail da un URL (es. pubblicato su HTTPS) e lancia il wrapper root install.sh
# Uso:
#   LIMRISTEM_MAIL_PACKAGE_URL=https://host/path/limristem-mail.tar.gz bash wget-install.sh
#   bash wget-install.sh https://host/path/limristem-mail.tar.gz

PKG_URL=${LIMRISTEM_MAIL_PACKAGE_URL:-${1:-}}
PKG_SHA256=${LIMRISTEM_MAIL_PACKAGE_SHA256:-${2:-}}
INSTALL_DIR=${LIMRISTEM_MAIL_INSTALL_DIR:-/opt/limristem-mail}

if [[ -z "$PKG_URL" ]]; then
  echo "[limristem-mail] Specifica l'URL dell'archivio tar.gz (LIMRISTEM_MAIL_PACKAGE_URL o primo argomento)" >&2
  exit 1
fi
case "$PKG_URL" in
  https://*) ;;
  *)
    echo "[limristem-mail] L'URL del pacchetto deve usare HTTPS" >&2
    exit 1
    ;;
esac

if [[ ! "$PKG_SHA256" =~ ^[A-Fa-f0-9]{64}$ ]]; then
  echo "[limristem-mail] Specifica obbligatoriamente lo SHA-256 atteso come secondo argomento o LIMRISTEM_MAIL_PACKAGE_SHA256" >&2
  exit 1
fi

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
pkg_file="$tmpdir/limristem-mail.tar.gz"

command -v wget >/dev/null 2>&1 || {
  echo "[limristem-mail] Comando richiesto non trovato: wget" >&2
  exit 1
}
command -v python3 >/dev/null 2>&1 || {
  echo "[limristem-mail] Comando richiesto non trovato: python3" >&2
  exit 1
}

echo "[limristem-mail] Download da $PKG_URL"
wget -O "$pkg_file" "$PKG_URL"

echo "[limristem-mail] Verifico SHA-256 dell'archivio"
echo "${PKG_SHA256}  ${pkg_file}" | sha256sum -c -

echo "[limristem-mail] Estrazione in $INSTALL_DIR"
mkdir -p "$INSTALL_DIR"
python3 - "$pkg_file" "$INSTALL_DIR" <<'PY'
import os
import shutil
import stat
import sys
import tarfile
from pathlib import Path, PurePosixPath

archive_path = Path(sys.argv[1])
destination = Path(sys.argv[2])
max_extracted_bytes = 512 * 1024 * 1024


def fail(message: str) -> None:
    raise SystemExit(f"[limristem-mail] Archivio non sicuro: {message}")


def normalized_parts(name: str) -> tuple[str, ...]:
    path = PurePosixPath(name)
    parts = tuple(part for part in path.parts if part not in ("", "."))
    if path.is_absolute() or not parts or ".." in parts:
        fail("contiene percorsi assoluti, vuoti o traversal")
    return parts


def ensure_safe_directory(path: Path) -> None:
    relative = path.relative_to(destination)
    current = destination
    for part in relative.parts:
        current = current / part
        if current.exists() or current.is_symlink():
            if current.is_symlink() or not current.is_dir():
                fail(f"il percorso di destinazione non è una directory sicura: {relative}")
        else:
            current.mkdir(mode=0o755)


destination.mkdir(parents=True, exist_ok=True)
if destination.is_symlink() or not destination.is_dir():
    fail("la destinazione non è una directory sicura")

try:
    with tarfile.open(archive_path, mode="r:gz") as archive:
        members = archive.getmembers()
        if not members:
            fail("è vuoto")

        parsed: list[tuple[tarfile.TarInfo, tuple[str, ...]]] = []
        total_size = 0
        seen_paths: set[tuple[str, ...]] = set()
        for member in members:
            parts = normalized_parts(member.name)
            if member.issym() or member.islnk() or member.isdev() or member.isfifo():
                fail("contiene link, device o FIFO")
            if not member.isdir() and not member.isfile():
                fail("contiene un tipo di file non supportato")
            if parts in seen_paths:
                fail(f"contiene percorsi duplicati: {'/'.join(parts)}")
            seen_paths.add(parts)
            total_size += max(member.size, 0)
            if total_size > max_extracted_bytes:
                fail("la dimensione estratta supera 512 MiB")
            parsed.append((member, parts))

        file_paths = {parts for member, parts in parsed if member.isfile()}
        required = {("install.sh",), ("version.json",)}
        prefix: tuple[str, ...] = ()
        if not required.issubset(file_paths):
            roots = {parts[0] for _, parts in parsed}
            if len(roots) != 1:
                fail("install.sh e version.json non sono presenti alla radice")
            root = next(iter(roots))
            prefix = (root,)
            required_prefixed = {(root, "install.sh"), (root, "version.json")}
            if not required_prefixed.issubset(file_paths):
                fail("install.sh e version.json non sono presenti nel pacchetto")

        extracted_paths: set[Path] = set()
        for member, parts in parsed:
            relative_parts = parts[len(prefix) :]
            if not relative_parts:
                continue
            target = destination.joinpath(*relative_parts)
            if target in extracted_paths:
                fail(f"più elementi producono lo stesso percorso: {'/'.join(relative_parts)}")
            extracted_paths.add(target)

            if member.isdir():
                ensure_safe_directory(target)
                continue

            ensure_safe_directory(target.parent)
            if target.exists() or target.is_symlink():
                target_mode = target.lstat().st_mode
                if stat.S_ISLNK(target_mode) or not stat.S_ISREG(target_mode):
                    fail(f"il file di destinazione non è sicuro: {'/'.join(relative_parts)}")
            source = archive.extractfile(member)
            if source is None:
                fail(f"impossibile leggere: {'/'.join(relative_parts)}")
            flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
            if hasattr(os, "O_NOFOLLOW"):
                flags |= os.O_NOFOLLOW
            fd = os.open(target, flags, 0o600)
            try:
                with os.fdopen(fd, "wb") as output:
                    shutil.copyfileobj(source, output)
            finally:
                source.close()
            safe_mode = 0o755 if member.mode & 0o111 else 0o644
            target.chmod(safe_mode)
except (OSError, tarfile.TarError) as exc:
    fail(f"non è un tar.gz valido: {exc}")
PY

cd "$INSTALL_DIR"
if [[ ! -f install.sh ]]; then
  echo "[limristem-mail] install.sh non trovato dentro l'archivio" >&2
  exit 1
fi

echo "[limristem-mail] Avvio install.sh (richiede root)"
bash install.sh

echo "[limristem-mail] Installazione completata"
