Fix setup/auth flow and harden storage write failures

This commit is contained in:
2026-04-11 19:24:44 +02:00
parent 4b95cc3dcb
commit eba5f915c1
3 changed files with 40 additions and 9 deletions
+15 -4
View File
@@ -30,6 +30,12 @@ final class App
$hasUsers = $this->users->hasAnyUsers(); $hasUsers = $this->users->hasAnyUsers();
$isAuthenticated = $this->auth->check(); $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 (!$hasUsers) {
if ($path === '/login') { if ($path === '/login') {
$path = '/setup'; $path = '/setup';
@@ -130,10 +136,15 @@ final class App
redirect('/setup'); redirect('/setup');
} }
$user = $this->users->create($username, $password, true); try {
$this->auth->login($user); $user = $this->users->create($username, $password, true);
flash('success', 'Der erste Account wurde erstellt. Du kannst direkt loslegen.'); $this->auth->login($user);
redirect('/'); 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 private function showLogin(): void
+14 -3
View File
@@ -69,7 +69,13 @@ final class UserRepository
$this->write(['users' => $users]); $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 public function changePassword(string $username, string $password): void
@@ -94,9 +100,14 @@ final class UserRepository
mkdir(dirname($this->path), 0775, true); mkdir(dirname($this->path), 0775, true);
} }
file_put_contents( $bytes = file_put_contents(
$this->path, $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.');
}
} }
} }
+11 -2
View File
@@ -10,7 +10,13 @@ final class Auth
public function check(): bool 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 public function user(): ?array
@@ -37,6 +43,10 @@ final class Auth
public function login(array $user): void 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_regenerate_id(true);
$_SESSION['user'] = [ $_SESSION['user'] = [
@@ -51,4 +61,3 @@ final class Auth
session_regenerate_id(true); session_regenerate_id(true);
} }
} }