<?php

declare(strict_types=1);

$baseDir = __DIR__;
$manifestFile = $baseDir . "/manifest.json";

function updateServerPackageError(int $status, string $message): void
{
    http_response_code($status);
    header("Content-Type: text/plain; charset=utf-8");
    echo $message;
    exit;
}

function updateServerPackageValidVersion(string $version): bool
{
    return preg_match('/^v\d+\.\d+\.\d+$/', $version) === 1;
}

$version = trim((string) ($_GET["version"] ?? ""));
if (!updateServerPackageValidVersion($version)) {
    updateServerPackageError(400, "Invalid version.");
}

if (!is_file($manifestFile)) {
    updateServerPackageError(500, "Manifest file is missing.");
}

$decoded = json_decode((string) file_get_contents($manifestFile), true);
if (!is_array($decoded)) {
    updateServerPackageError(500, "Manifest file is not valid JSON.");
}

$releases = isset($decoded["releases"]) && is_array($decoded["releases"])
    ? $decoded["releases"]
    : [];
if (!isset($releases[$version]) || !is_array($releases[$version])) {
    updateServerPackageError(404, "Release is not configured.");
}

$release = $releases[$version];
$releaseVersion = trim((string) ($release["version"] ?? $version));
$sha256 = strtolower(trim((string) ($release["sha256"] ?? "")));
$package = trim((string) ($release["package"] ?? ""));
if ($releaseVersion !== $version || !updateServerPackageValidVersion($releaseVersion)) {
    updateServerPackageError(500, "Release version is invalid.");
}
if (!preg_match('/^[a-f0-9]{64}$/', $sha256)) {
    updateServerPackageError(500, "Release checksum is invalid.");
}
if ($package === "" || str_contains($package, "\0") || str_starts_with($package, "/")) {
    updateServerPackageError(500, "Release package path is invalid.");
}

$packagePath = realpath($baseDir . "/" . $package);
$packagesDir = realpath($baseDir . "/packages");
if (
    $packagePath === false ||
    $packagesDir === false ||
    !str_starts_with($packagePath, $packagesDir . DIRECTORY_SEPARATOR) ||
    !is_file($packagePath)
) {
    updateServerPackageError(404, "Release package is missing.");
}

if (strtolower(pathinfo($packagePath, PATHINFO_EXTENSION)) !== "zip") {
    updateServerPackageError(500, "Release package is not a ZIP file.");
}

$fileName = basename($packagePath);
$fileSize = filesize($packagePath);
$handle = fopen($packagePath, "rb");
if ($fileSize === false || $handle === false) {
    updateServerPackageError(500, "Release package cannot be opened.");
}

header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=\"" . addcslashes($fileName, "\"\\") . "\"");
header("Content-Length: " . (string) $fileSize);
header("Cache-Control: public, max-age=300");
header("X-Content-Type-Options: nosniff");

fpassthru($handle);
fclose($handle);
