- 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>
82 lines
3.4 KiB
PHP
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);
|
|
}
|
|
}
|