auth.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <?php
  2. declare(strict_types=1);
  3. // Admin session, password check and CSRF for the management UI. One shared
  4. // implementation for the release and backup areas.
  5. require_once __DIR__ . "/bootstrap.php";
  6. function manageStartSession(): void
  7. {
  8. if (session_status() !== PHP_SESSION_NONE) {
  9. return;
  10. }
  11. $isHttps =
  12. (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off") ||
  13. (isset($_SERVER["SERVER_PORT"]) && (int) $_SERVER["SERVER_PORT"] === 443) ||
  14. strtolower((string) ($_SERVER["HTTP_X_FORWARDED_PROTO"] ?? "")) === "https";
  15. ini_set("session.use_strict_mode", "1");
  16. ini_set("session.cookie_httponly", "1");
  17. ini_set("session.cookie_secure", $isHttps ? "1" : "0");
  18. ini_set("session.cookie_samesite", "Lax");
  19. session_name("manage_session");
  20. session_start();
  21. }
  22. function managePasswordConfigured(): bool
  23. {
  24. if (defined("MANAGE_ADMIN_PASSWORD_HASH")) {
  25. $hash = trim((string) MANAGE_ADMIN_PASSWORD_HASH);
  26. if ($hash !== "" && !str_contains($hash, "replace-this")) {
  27. return true;
  28. }
  29. }
  30. return defined("MANAGE_ADMIN_PASSWORD") && trim((string) MANAGE_ADMIN_PASSWORD) !== "";
  31. }
  32. function managePasswordMatches(string $password): bool
  33. {
  34. if (defined("MANAGE_ADMIN_PASSWORD_HASH")) {
  35. $hash = trim((string) MANAGE_ADMIN_PASSWORD_HASH);
  36. if ($hash !== "" && !str_contains($hash, "replace-this")) {
  37. return password_verify($password, $hash);
  38. }
  39. }
  40. if (defined("MANAGE_ADMIN_PASSWORD")) {
  41. return hash_equals((string) MANAGE_ADMIN_PASSWORD, $password);
  42. }
  43. return false;
  44. }
  45. function manageIsLoggedIn(): bool
  46. {
  47. return !empty($_SESSION["manage_logged_in"]);
  48. }
  49. function manageLogin(): void
  50. {
  51. session_regenerate_id(true);
  52. $_SESSION["manage_logged_in"] = true;
  53. $_SESSION["manage_logged_in_at"] = time();
  54. }
  55. function manageLogout(): void
  56. {
  57. unset(
  58. $_SESSION["manage_logged_in"],
  59. $_SESSION["manage_logged_in_at"],
  60. $_SESSION["manage_csrf_token"],
  61. );
  62. }
  63. // Redirects to the login page instead of rendering. Every admin page calls this
  64. // as its first statement after the includes.
  65. function manageRequireLogin(): void
  66. {
  67. manageStartSession();
  68. if (manageIsLoggedIn()) {
  69. return;
  70. }
  71. $target = basename((string) ($_SERVER["SCRIPT_NAME"] ?? ""));
  72. header("Location: login.php?next=" . rawurlencode($target));
  73. exit;
  74. }
  75. function manageCsrfToken(): string
  76. {
  77. if (empty($_SESSION["manage_csrf_token"])) {
  78. $_SESSION["manage_csrf_token"] = bin2hex(random_bytes(32));
  79. }
  80. return (string) $_SESSION["manage_csrf_token"];
  81. }
  82. function manageCsrfIsValid(string $token): bool
  83. {
  84. return !empty($_SESSION["manage_csrf_token"]) &&
  85. hash_equals((string) $_SESSION["manage_csrf_token"], $token);
  86. }
  87. function manageCsrfField(): string
  88. {
  89. return '<input type="hidden" name="csrf_token" value="' .
  90. manageEscape(manageCsrfToken()) .
  91. '">';
  92. }
  93. // Guard for every mutating POST in the admin UI.
  94. function manageRequireCsrf(): void
  95. {
  96. if (!manageCsrfIsValid((string) ($_POST["csrf_token"] ?? ""))) {
  97. throw new RuntimeException(
  98. "Ungültiges Sicherheitstoken. Bitte die Seite neu laden und erneut versuchen.",
  99. );
  100. }
  101. }