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>
This commit is contained in:
81
app/Http/Middleware/InstallerMiddleware.php
Normal file
81
app/Http/Middleware/InstallerMiddleware.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user