Files
WebAPP/app/Http/Middleware/InstallerMiddleware.php
Rhino 2e24a40d68 Stand: SMTP-Test, Admin-Mail-Tab, Notifiable-Fix, Lazy-Quill
- Fix: Notifiable-Trait zum User-Model hinzugefuegt (behebt notify()-500er)
- Installer: SMTP-Verbindungstest mit EsmtpTransport + Ueberspringen-Link
- Admin: Neuer E-Mail-Tab mit SMTP-Konfiguration + Verbindungstest
- Admin: Lazy Quill-Initialisierung (nur sichtbare Locale wird geladen)
- Uebersetzungen: 17 neue Mail-Keys in allen 6 Sprachen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:30:37 +01:00

82 lines
3.4 KiB
PHP

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class InstallerMiddleware
{
public function handle(Request $request, Closure $next): Response
{
// Auto-create .env from .env.example if missing (first-time deployment)
$envPath = base_path('.env');
if (! file_exists($envPath) && file_exists(base_path('.env.example'))) {
copy(base_path('.env.example'), $envPath);
}
$isInstalled = file_exists(storage_path('installed'));
$isInstallerRoute = $request->is('install') || $request->is('install/*');
// Not installed + not on installer routes → redirect to installer
if (! $isInstalled && ! $isInstallerRoute) {
// Allow static assets and health check through
if ($request->is('favicon.ico', 'images/*', 'up', 'manifest.json', 'sw.js', 'storage/*')) {
return $next($request);
}
return redirect('/install');
}
// Already installed + on installer routes → redirect to login
if ($isInstalled && $isInstallerRoute) {
return redirect('/login');
}
// Setup-Token-Schutz: Installer nur mit gültigem Token erreichbar
if (! $isInstalled && $isInstallerRoute) {
$tokenFile = storage_path('setup-token');
// Token-Datei beim ersten Zugriff generieren
if (! file_exists($tokenFile)) {
$token = bin2hex(random_bytes(16));
file_put_contents($tokenFile, $token);
chmod($tokenFile, 0600);
// Nur Token-Hash loggen (Klartext in Datei storage/setup-token)
logger()->warning("Installer Setup-Token generiert (SHA256: " . hash('sha256', $token) . ")");
logger()->warning("Token befindet sich in: storage/setup-token");
}
$expectedToken = trim(file_get_contents($tokenFile));
$providedToken = $request->query('token');
// Session ist ggf. noch nicht gestartet (Middleware laeuft vor StartSession)
$sessionTokenHash = $request->hasSession() ? $request->session()->get('setup_token_hash') : null;
if ($providedToken && hash_equals($expectedToken, $providedToken)) {
// Token-Hash in Session speichern — kein Klartext in Session (V11)
if ($request->hasSession()) {
$request->session()->put('setup_token_hash', hash('sha256', $expectedToken));
}
} elseif ($sessionTokenHash && hash_equals(hash('sha256', $expectedToken), $sessionTokenHash)) {
// Gültiges Token via Session-Hash
} elseif (! $request->is('install')) {
// Nur die Startseite ohne Token erlauben (zeigt Token-Eingabe)
abort(403, 'Ungültiges Setup-Token.');
}
}
// Force file-based session/cache during installation (DB may not exist yet).
// Fixed cookie name prevents session loss when APP_NAME changes in .env mid-install.
if (! $isInstalled && $isInstallerRoute) {
config([
'session.driver' => 'file',
'cache.default' => 'file',
'session.cookie' => 'handball_installer_session',
]);
}
return $next($request);
}
}