From eba5f915c1198d1382f4b08e45b4480c8c41a5c5 Mon Sep 17 00:00:00 2001 From: Florian Heinz Date: Sat, 11 Apr 2026 19:24:44 +0200 Subject: [PATCH] Fix setup/auth flow and harden storage write failures --- src/App.php | 19 +++++++++++++++---- src/Domain/UserRepository.php | 17 ++++++++++++++--- src/Support/Auth.php | 13 +++++++++++-- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/App.php b/src/App.php index 403a922..6b5596e 100644 --- a/src/App.php +++ b/src/App.php @@ -30,6 +30,12 @@ final class App $hasUsers = $this->users->hasAnyUsers(); $isAuthenticated = $this->auth->check(); + // A failed setup must never leave the app in a half-authenticated redirect loop. + if (!$hasUsers && $isAuthenticated) { + $this->auth->logout(); + $isAuthenticated = false; + } + if (!$hasUsers) { if ($path === '/login') { $path = '/setup'; @@ -130,10 +136,15 @@ final class App redirect('/setup'); } - $user = $this->users->create($username, $password, true); - $this->auth->login($user); - flash('success', 'Der erste Account wurde erstellt. Du kannst direkt loslegen.'); - redirect('/'); + try { + $user = $this->users->create($username, $password, true); + $this->auth->login($user); + flash('success', 'Der erste Account wurde erstellt. Du kannst direkt loslegen.'); + redirect('/'); + } catch (RuntimeException $exception) { + flash('error', $exception->getMessage()); + redirect('/setup'); + } } private function showLogin(): void diff --git a/src/Domain/UserRepository.php b/src/Domain/UserRepository.php index 523ab1b..cff3e75 100644 --- a/src/Domain/UserRepository.php +++ b/src/Domain/UserRepository.php @@ -69,7 +69,13 @@ final class UserRepository $this->write(['users' => $users]); - return $this->find($normalized) ?? []; + $createdUser = $this->find($normalized); + + if ($createdUser === null) { + throw new RuntimeException('Der Account konnte nicht gespeichert werden.'); + } + + return $createdUser; } public function changePassword(string $username, string $password): void @@ -94,9 +100,14 @@ final class UserRepository mkdir(dirname($this->path), 0775, true); } - file_put_contents( + $bytes = file_put_contents( $this->path, - json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) + json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + LOCK_EX ); + + if ($bytes === false) { + throw new RuntimeException('Die Benutzerdatei konnte nicht geschrieben werden. Bitte prüfe die Schreibrechte von storage/system.'); + } } } diff --git a/src/Support/Auth.php b/src/Support/Auth.php index 0971d09..a2c53aa 100644 --- a/src/Support/Auth.php +++ b/src/Support/Auth.php @@ -10,7 +10,13 @@ final class Auth public function check(): bool { - return isset($_SESSION['user']) && is_array($_SESSION['user']); + if (!isset($_SESSION['user']) || !is_array($_SESSION['user'])) { + return false; + } + + $username = $_SESSION['user']['username'] ?? null; + + return is_string($username) && $username !== ''; } public function user(): ?array @@ -37,6 +43,10 @@ final class Auth public function login(array $user): void { + if (!isset($user['username']) || !is_string($user['username']) || $user['username'] === '') { + throw new RuntimeException('Der Benutzer konnte nicht angemeldet werden.'); + } + session_regenerate_id(true); $_SESSION['user'] = [ @@ -51,4 +61,3 @@ final class Auth session_regenerate_id(true); } } -