package.php 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. <?php
  2. // DEPRECATED: The bundled update server is deprecated and unmaintained.
  3. // It is kept for reference only and will be removed in a future release.
  4. // Do not deploy it for new installations.
  5. declare(strict_types=1);
  6. $baseDir = __DIR__;
  7. $manifestFile = $baseDir . "/manifest.json";
  8. function updateServerPackageError(int $status, string $message): void
  9. {
  10. http_response_code($status);
  11. header("Content-Type: text/plain; charset=utf-8");
  12. echo $message;
  13. exit;
  14. }
  15. function updateServerPackageValidVersion(string $version): bool
  16. {
  17. return preg_match('/^v\d+\.\d+\.\d+$/', $version) === 1;
  18. }
  19. $version = trim((string) ($_GET["version"] ?? ""));
  20. if (!updateServerPackageValidVersion($version)) {
  21. updateServerPackageError(400, "Invalid version.");
  22. }
  23. if (!is_file($manifestFile)) {
  24. updateServerPackageError(500, "Manifest file is missing.");
  25. }
  26. $decoded = json_decode((string) file_get_contents($manifestFile), true);
  27. if (!is_array($decoded)) {
  28. updateServerPackageError(500, "Manifest file is not valid JSON.");
  29. }
  30. $releases = isset($decoded["releases"]) && is_array($decoded["releases"])
  31. ? $decoded["releases"]
  32. : [];
  33. if (!isset($releases[$version]) || !is_array($releases[$version])) {
  34. updateServerPackageError(404, "Release is not configured.");
  35. }
  36. $release = $releases[$version];
  37. $releaseVersion = trim((string) ($release["version"] ?? $version));
  38. $sha256 = strtolower(trim((string) ($release["sha256"] ?? "")));
  39. $package = trim((string) ($release["package"] ?? ""));
  40. if ($releaseVersion !== $version || !updateServerPackageValidVersion($releaseVersion)) {
  41. updateServerPackageError(500, "Release version is invalid.");
  42. }
  43. if (!preg_match('/^[a-f0-9]{64}$/', $sha256)) {
  44. updateServerPackageError(500, "Release checksum is invalid.");
  45. }
  46. if ($package === "" || str_contains($package, "\0") || str_starts_with($package, "/")) {
  47. updateServerPackageError(500, "Release package path is invalid.");
  48. }
  49. $packagePath = realpath($baseDir . "/" . $package);
  50. $packagesDir = realpath($baseDir . "/packages");
  51. if (
  52. $packagePath === false ||
  53. $packagesDir === false ||
  54. !str_starts_with($packagePath, $packagesDir . DIRECTORY_SEPARATOR) ||
  55. !is_file($packagePath)
  56. ) {
  57. updateServerPackageError(404, "Release package is missing.");
  58. }
  59. if (strtolower(pathinfo($packagePath, PATHINFO_EXTENSION)) !== "zip") {
  60. updateServerPackageError(500, "Release package is not a ZIP file.");
  61. }
  62. $fileName = basename($packagePath);
  63. $fileSize = filesize($packagePath);
  64. $handle = fopen($packagePath, "rb");
  65. if ($fileSize === false || $handle === false) {
  66. updateServerPackageError(500, "Release package cannot be opened.");
  67. }
  68. header("Content-Type: application/zip");
  69. header("Content-Disposition: attachment; filename=\"" . addcslashes($fileName, "\"\\") . "\"");
  70. header("Content-Length: " . (string) $fileSize);
  71. header("Cache-Control: public, max-age=300");
  72. header("X-Content-Type-Options: nosniff");
  73. fpassthru($handle);
  74. fclose($handle);