Files
nexus/public/index.php
2026-03-05 02:10:21 +01:00

151 lines
4.7 KiB
PHP
Executable File

<?php
declare(strict_types=1);
// boot application (config, autoload, services)
require_once __DIR__ . '/../config/fileload.php';
// Access-Protection (Basic Auth)
$uriPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
$uriPath = preg_replace('~/{2,}~', '/', $uriPath);
$uriPath = trim($uriPath, '/');
$isRetoolPath = ($uriPath === 'retool' || str_starts_with($uriPath, 'retool/'));
if (defined('APP_BASIC_AUTH') && APP_BASIC_AUTH && !$isRetoolPath) {
$authUser = getenv('STAGING_AUTH_USER') ?: 'staging';
$authPass = getenv('STAGING_AUTH_PASS') ?: 'staging123';
$user = $_SERVER['PHP_AUTH_USER'] ?? null;
$pass = $_SERVER['PHP_AUTH_PW'] ?? null;
if ($user !== $authUser || $pass !== $authPass) {
header('WWW-Authenticate: Basic realm="Staging"');
header('HTTP/1.0 401 Unauthorized');
echo 'Unauthorized';
exit;
}
}
// OIDC Auth
$publicPaths = [
'auth/login',
'auth/callback',
'auth/logout',
'module/pi_control/terminal_info',
];
if (defined('APP_AUTH_ENABLED') && APP_AUTH_ENABLED && !in_array($uriPath, $publicPaths, true)) {
$user = auth_user();
if (!$user) {
header('Location: /auth/login', true, 302);
exit;
}
}
// Sicherheitscheck
if (str_contains($uriPath, '..')) {
http_response_code(400);
exit('Bad request');
}
// Basispfad fuer Landingpages
$pagesBase = realpath(__DIR__ . '/../partials/landingpages') ?: (__DIR__ . '/../partials/landingpages');
$page404 = $pagesBase . '/errorpages/404.php';
// Spezialrouten für Module
if (str_starts_with($uriPath, 'modules/install')) {
$target = $pagesBase . '/modules/install.php';
} elseif (str_starts_with($uriPath, 'modules/setup/')) {
$_GET['module'] = trim(substr($uriPath, strlen('modules/setup/')), '/');
$target = $pagesBase . '/modules/setup.php';
} elseif ($uriPath === 'auth/login') {
$target = $pagesBase . '/auth/login.php';
} elseif ($uriPath === 'auth/callback') {
$target = $pagesBase . '/auth/callback.php';
} elseif ($uriPath === 'auth/logout') {
$target = $pagesBase . '/auth/logout.php';
} elseif ($uriPath === 'settings') {
$target = $pagesBase . '/users/settings.php';
} elseif ($uriPath === 'users') {
$target = $pagesBase . '/users/index.php';
} elseif ($uriPath === 'debug') {
$target = $pagesBase . '/retool/debug.php';
} elseif (preg_match('~^module/([a-zA-Z0-9_-]+)(?:/(.+))?$~', $uriPath, $m)) {
$module = $m[1];
$page = isset($m[2]) && $m[2] !== '' ? trim($m[2], '/') : 'index';
$modulePage = app()->modules()->resolvePage($module, $page);
if ($modulePage) {
$target = $modulePage;
} else {
http_response_code(404);
$target = $page404;
}
} elseif ($uriPath === '' || $uriPath === 'index' || $uriPath === 'index.php') {
$target = $pagesBase . '/index.php';
} else {
$base = $pagesBase . '/' . $uriPath;
// 1) Verzeichnis mit index.php
if (is_dir($base) && is_file($base . '/index.php')) {
$target = $base . '/index.php';
}
// 2) Datei
elseif (is_file($base . '.php')) {
$target = $base . '.php';
}
// 3) 404
elseif (is_file($base)) {
$target = $base;
}
// 3) 404
else {
http_response_code(404);
$target = $page404;
}
}
// ------------------------------------
// Layout-Regel
// ------------------------------------
$skipLayout = false;
$targetReal = realpath($target);
$retoolBase = realpath($pagesBase . '/retool/raw');
// Beispiel: alles unter landingpages/retool/* ohne Layout
if ($targetReal && $retoolBase && str_starts_with($targetReal, $retoolBase)) {
$skipLayout = true;
}
// ------------------------------------
// Ausgabe
// ------------------------------------
// Erst Inhalt laden (ohne Ausgabe), damit Header/Redirects vor HTML funktionieren
ob_start();
try {
require $target;
$content = ob_get_clean();
} catch (\App\ModuleConfigException $e) {
ob_end_clean();
http_response_code(412);
$moduleName = $e->module();
$module = app()->modules()->get($moduleName);
$title = $module['title'] ?? $moduleName;
$setupUrl = '/modules/setup/' . rawurlencode($moduleName);
$content = '<div class="card">' .
'<div class="pill">' . e($title) . '</div>' .
'<h1 style="margin-top:.75rem;">Setup erforderlich</h1>' .
'<p class="muted">' . e($e->getMessage()) . '</p>' .
'<div style="margin-top:1rem;"><a class="nav-link" href="' . e($setupUrl) . '">Zum Setup</a></div>' .
'</div>';
}
// Wenn bereits Header gesendet wurden (z. B. eigener Redirect/Content-Type), Layout überspringen
if (headers_sent()) {
$skipLayout = true;
}
if (!$skipLayout) {
tpl('layout_start', 'structure');
}
echo $content;
if (!$skipLayout) {
tpl('layout_end', 'structure');
}