manifest.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. header("Content-Type: application/json; charset=utf-8");
  7. header("Cache-Control: no-store");
  8. $baseDir = __DIR__;
  9. $manifestFile = $baseDir . "/manifest.json";
  10. function updateServerRespond(int $status, array $payload): void
  11. {
  12. http_response_code($status);
  13. echo json_encode(
  14. $payload,
  15. JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE,
  16. );
  17. exit;
  18. }
  19. function updateServerValidateVersion(string $version): bool
  20. {
  21. return preg_match('/^v\d+\.\d+\.\d+$/', $version) === 1;
  22. }
  23. function updateServerNormalizePackageUrl(string $version): string
  24. {
  25. $scheme = "http";
  26. if (
  27. (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off") ||
  28. (isset($_SERVER["SERVER_PORT"]) && (int) $_SERVER["SERVER_PORT"] === 443) ||
  29. strtolower((string) ($_SERVER["HTTP_X_FORWARDED_PROTO"] ?? "")) === "https"
  30. ) {
  31. $scheme = "https";
  32. }
  33. $host = $_SERVER["HTTP_HOST"] ?? "localhost";
  34. $scriptDir = rtrim(str_replace("\\", "/", dirname($_SERVER["SCRIPT_NAME"] ?? "")), "/");
  35. return $scheme .
  36. "://" .
  37. $host .
  38. ($scriptDir === "" ? "" : $scriptDir) .
  39. "/package.php?version=" .
  40. rawurlencode($version);
  41. }
  42. if (!is_file($manifestFile)) {
  43. updateServerRespond(500, ["error" => "Manifest file is missing."]);
  44. }
  45. $decoded = json_decode((string) file_get_contents($manifestFile), true);
  46. if (!is_array($decoded)) {
  47. updateServerRespond(500, ["error" => "Manifest file is not valid JSON."]);
  48. }
  49. $latest = trim((string) ($decoded["latest"] ?? ""));
  50. $releases = isset($decoded["releases"]) && is_array($decoded["releases"])
  51. ? $decoded["releases"]
  52. : [];
  53. if ($latest === "" || !updateServerValidateVersion($latest)) {
  54. updateServerRespond(404, ["error" => "No valid latest release is configured."]);
  55. }
  56. if (!isset($releases[$latest]) || !is_array($releases[$latest])) {
  57. updateServerRespond(404, ["error" => "Latest release entry is missing."]);
  58. }
  59. $release = $releases[$latest];
  60. $version = trim((string) ($release["version"] ?? $latest));
  61. $package = trim((string) ($release["package"] ?? ""));
  62. $sha256 = strtolower(trim((string) ($release["sha256"] ?? "")));
  63. $publishedAt = trim((string) ($release["published_at"] ?? ""));
  64. $size = isset($release["size"]) ? (int) $release["size"] : 0;
  65. if ($version !== $latest || !updateServerValidateVersion($version)) {
  66. updateServerRespond(500, ["error" => "Latest release version is invalid."]);
  67. }
  68. if ($package === "" || str_contains($package, "\0") || str_starts_with($package, "/")) {
  69. updateServerRespond(500, ["error" => "Latest release package path is invalid."]);
  70. }
  71. if (!preg_match('/^[a-f0-9]{64}$/', $sha256)) {
  72. updateServerRespond(500, ["error" => "Latest release checksum is invalid."]);
  73. }
  74. $packagePath = realpath($baseDir . "/" . $package);
  75. $packagesDir = realpath($baseDir . "/packages");
  76. if (
  77. $packagePath === false ||
  78. $packagesDir === false ||
  79. !str_starts_with($packagePath, $packagesDir . DIRECTORY_SEPARATOR) ||
  80. !is_file($packagePath)
  81. ) {
  82. updateServerRespond(404, ["error" => "Latest release package is missing."]);
  83. }
  84. if ($size <= 0) {
  85. $size = filesize($packagePath) ?: 0;
  86. }
  87. updateServerRespond(200, [
  88. "latest" => $latest,
  89. "version" => $version,
  90. "package_url" => updateServerNormalizePackageUrl($version),
  91. "sha256" => $sha256,
  92. "size" => $size,
  93. "published_at" => $publishedAt,
  94. ]);