time(); } function raijuAccessAssetPath(string $path): string { $path = trim($path); if ($path === '') { return ''; } if (preg_match('#^https?://#i', $path)) { return ''; } return '/' . ltrim($path, '/'); } function raijuAccessResolveBrandAsset(array $settings, string $asset): string { if ($asset === 'favicon') { return raijuAccessAssetPath((string)($settings['favicon'] ?? '/assets/images/favicon.svg')); } if ($asset === 'logo') { $logo = (string)($settings['branding']['logo'] ?? ''); return raijuAccessAssetPath($logo !== '' ? $logo : (string)($settings['favicon'] ?? '/assets/images/favicon.svg')); } return ''; } function raijuAccessCssUrl(string $path): string { return str_replace(["\\", "\"", "\n", "\r"], ["\\\\", "\\\"", "", ""], $path); } function raijuAccessImageLayout(string $layout): string { if ($layout === 'split') { return 'left'; } return in_array($layout, ['none', 'background', 'left', 'right'], true) ? $layout : 'none'; } function raijuAccessRgbaFromHex(string $hex, int $opacity): string { if (!preg_match('/^#[0-9a-fA-F]{6}$/', $hex)) { return ''; } $opacity = max(0, min(100, $opacity)); $red = hexdec(substr($hex, 1, 2)); $green = hexdec(substr($hex, 3, 2)); $blue = hexdec(substr($hex, 5, 2)); $alpha = rtrim(rtrim(sprintf('%.2F', $opacity / 100), '0'), '.'); return "rgba($red, $green, $blue, $alpha)"; } function raijuAccessRenderStandalonePage(array $options): void { $status = (int)($options['status'] ?? 503); http_response_code($status); if ($status === 503 && !empty($options['retryAfter'])) { header('Retry-After: ' . (int)$options['retryAfter']); } header('Content-Type: text/html; charset=utf-8'); header('X-Robots-Tag: noindex, nofollow', false); $title = htmlspecialchars((string)($options['title'] ?? 'Temporarily unavailable'), ENT_QUOTES, 'UTF-8'); $text = nl2br(htmlspecialchars((string)($options['text'] ?? ''), ENT_QUOTES, 'UTF-8')); $mode = htmlspecialchars((string)($options['mode'] ?? 'maintenance'), ENT_QUOTES, 'UTF-8'); $until = htmlspecialchars((string)($options['until'] ?? ''), ENT_QUOTES, 'UTF-8'); $showCountdown = !empty($options['showCountdown']) && $until !== ''; $brandAsset = raijuAccessAssetPath((string)($options['brandAssetPath'] ?? '')); $image = raijuAccessAssetPath((string)($options['image'] ?? '')); $imageLayout = $image !== '' ? raijuAccessImageLayout((string)($options['imageLayout'] ?? 'none')) : 'none'; $bodyClass = 'rj-lock-page'; if ($imageLayout === 'background') { $bodyClass .= ' rj-lock-page--background'; } elseif ($imageLayout === 'left') { $bodyClass .= ' rj-lock-page--split rj-lock-page--image-left'; } elseif ($imageLayout === 'right') { $bodyClass .= ' rj-lock-page--split rj-lock-page--image-right'; } $cssImage = raijuAccessCssUrl($image); $overlayColor = trim((string)($options['overlayColor'] ?? '')); $overlayOpacity = (int)($options['overlayOpacity'] ?? 88); $overlayRgba = raijuAccessRgbaFromHex($overlayColor, $overlayOpacity); $overlayStyle = $overlayColor !== '' && preg_match('/^#[0-9a-fA-F]{6}$/', $overlayColor) ? '; --rj-lock-overlay-color: ' . htmlspecialchars($overlayRgba, ENT_QUOTES, 'UTF-8') : ''; ?> <?php echo $title; ?> >

time()) { $retryAfter = min(86400, max(60, $untilTs - time())); } } raijuAccessRenderStandalonePage([ 'status' => 503, 'mode' => $maintenance['mode'] ?? 'maintenance', 'title' => $maintenance['title'] ?? 'Wartungsarbeiten', 'text' => $maintenance['text'] ?? 'Wir sind in Kürze wieder online.', 'until' => $until, 'showCountdown' => !empty($maintenance['showCountdown']), 'brandAssetPath' => raijuAccessResolveBrandAsset($settings, (string)($maintenance['brandAsset'] ?? 'none')), 'image' => $maintenance['image'] ?? '', 'imageLayout' => $maintenance['imageLayout'] ?? 'none', 'overlayColor' => $maintenance['overlayColor'] ?? '', 'overlayOpacity' => $maintenance['overlayOpacity'] ?? 88, 'retryAfter' => $retryAfter, ]); } function raijuAccessPageIsPrivate(array $pageData): bool { $visibility = $pageData['visibility'] ?? []; return is_array($visibility) && (($visibility['status'] ?? 'public') === 'private'); } function raijuAccessEnforcePage(string $contentPage, array $pageData): void { if (!raijuAccessPageIsPrivate($pageData) || raijuAccessIsLoggedIn()) { return; } raijuAccessStartSession(); $sessionKey = 'raiju_private_page_' . hash('sha256', $contentPage); $visibility = $pageData['visibility']; $passwordHash = (string)($visibility['passwordHash'] ?? ''); $grant = (string)($_SESSION[$sessionKey] ?? ''); if ($passwordHash !== '' && hash_equals(hash('sha256', $passwordHash), $grant)) { return; } $error = ''; if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && isset($_POST['raiju_page_password'])) { $password = (string)$_POST['raiju_page_password']; $hash = (string)($visibility['passwordHash'] ?? ''); if ($hash !== '' && password_verify($password, $hash)) { $_SESSION[$sessionKey] = hash('sha256', $hash); header('Location: ' . ($_SERVER['REQUEST_URI'] ?? '/')); exit; } $error = 'Das Passwort ist nicht korrekt.'; } raijuAccessRenderStandalonePage([ 'status' => 403, 'mode' => 'private', 'title' => $visibility['title'] ?? 'Geschützte Seite', 'text' => $visibility['text'] ?? 'Bitte gib das Passwort ein, um diese Seite zu öffnen.', 'form' => true, 'error' => $error, ]); } function raijuAccessEnforceCurrentTemplatePage(?string $contentPage): void { require_once __DIR__ . '/page-path.php'; if (!$contentPage || !raijuPageIsValidContentKey($contentPage)) { return; } $path = raijuAccessSiteRoot() . '/content/pages/' . $contentPage . '.json'; if (!is_file($path)) { return; } $data = json_decode((string)file_get_contents($path), true); if (!is_array($data)) { return; } raijuAccessEnforcePage($contentPage, $data); }