Add remember-me login and personalize sport presets

This commit is contained in:
2026-04-12 11:47:59 +02:00
parent 0e00dfdc40
commit a1135d37d8
14 changed files with 192 additions and 43 deletions
+3 -1
View File
@@ -170,7 +170,9 @@ final class App
redirect('/login');
}
if (!$this->auth->attempt($username, $password)) {
$remember = isset($_POST['remember_me']) && $_POST['remember_me'] === '1';
if (!$this->auth->attempt($username, $password, $remember)) {
$this->throttle->hit($throttleKey);
flash('error', 'Login fehlgeschlagen. Bitte prüfe Benutzername und Passwort.');
redirect('/login');
+19 -4
View File
@@ -16,7 +16,13 @@ final class Auth
$username = $_SESSION['user']['username'] ?? null;
return is_string($username) && $username !== '';
$valid = is_string($username) && $username !== '';
if ($valid && !empty($_SESSION['remember_me'])) {
setcookie(session_name(), session_id(), session_cookie_options_for(time() + remember_me_lifetime()));
}
return $valid;
}
public function user(): ?array
@@ -28,7 +34,7 @@ final class Auth
return $_SESSION['user'];
}
public function attempt(string $username, string $password): bool
public function attempt(string $username, string $password, bool $remember = false): bool
{
$user = $this->users->verify($username, $password);
@@ -36,12 +42,12 @@ final class Auth
return false;
}
$this->login($user);
$this->login($user, $remember);
return true;
}
public function login(array $user): void
public function login(array $user, bool $remember = false): void
{
if (!isset($user['username']) || !is_string($user['username']) || $user['username'] === '') {
throw new RuntimeException('Der Benutzer konnte nicht angemeldet werden.');
@@ -53,11 +59,20 @@ final class Auth
'username' => $user['username'],
'is_admin' => (bool) ($user['is_admin'] ?? false),
];
$_SESSION['remember_me'] = $remember;
if ($remember) {
setcookie(session_name(), session_id(), session_cookie_options_for(time() + remember_me_lifetime()));
} else {
setcookie(session_name(), session_id(), session_cookie_options_for());
}
}
public function logout(): void
{
unset($_SESSION['user']);
unset($_SESSION['remember_me']);
setcookie(session_name(), '', session_cookie_options_for(time() - 3600));
session_regenerate_id(true);
}
}
+57 -17
View File
@@ -17,22 +17,6 @@ final class Defaults
],
],
'sport_types' => [
[
'id' => 'strength-home',
'label' => 'Kraftsport (Keller)',
'icon' => 'strength-home',
'recovery_group' => 'kraftsport',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'strength-gym',
'label' => 'Kraftsport (Gym)',
'icon' => 'strength-gym',
'recovery_group' => 'kraftsport',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'running',
'label' => 'Joggen',
@@ -41,14 +25,70 @@ final class Defaults
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'cycling',
'label' => 'Radfahren',
'icon' => 'bike',
'recovery_group' => 'radfahren',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'strength',
'label' => 'Krafttraining',
'icon' => 'strength',
'recovery_group' => 'kraftsport',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'hiking',
'label' => 'Wandern',
'icon' => 'hike',
'recovery_group' => 'wandern',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'swimming',
'label' => 'Schwimmen',
'icon' => 'swim',
'recovery_group' => 'schwimmen',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'yoga',
'label' => 'Yoga',
'icon' => 'yoga',
'recovery_group' => 'yoga',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'hiit-workout',
'label' => 'HIIT / Workout',
'icon' => 'hiit',
'recovery_group' => 'hiit',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'rowing',
'label' => 'Rudergerät',
'label' => 'Rudern',
'icon' => 'row',
'recovery_group' => 'rudern',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'dance',
'label' => 'Tanzen',
'icon' => 'dance',
'recovery_group' => 'tanzen',
'bonus_points' => 2,
'allow_consecutive' => false,
],
[
'id' => 'core',
'label' => 'Core',
+2 -16
View File
@@ -15,26 +15,12 @@ require __DIR__ . '/App.php';
date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Berlin');
$forwardedProto = strtolower((string) ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''));
$forwardedSsl = strtolower((string) ($_SERVER['HTTP_X_FORWARDED_SSL'] ?? ''));
$isSecure = (
(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| $forwardedProto === 'https'
|| $forwardedSsl === 'on'
);
ini_set('session.use_only_cookies', '1');
ini_set('session.use_strict_mode', '1');
ini_set('session.gc_maxlifetime', (string) remember_me_lifetime());
session_name('mood_session');
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => '',
'secure' => $isSecure,
'httponly' => true,
'samesite' => 'Lax',
]);
session_set_cookie_params(session_cookie_params_for());
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
+50 -2
View File
@@ -176,6 +176,47 @@ function mood_icon_path(string $sentiment): string
return icon_path('mood-' . $sentiment);
}
function request_is_secure(): bool
{
$forwardedProto = strtolower((string) ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''));
$forwardedSsl = strtolower((string) ($_SERVER['HTTP_X_FORWARDED_SSL'] ?? ''));
return (
(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| $forwardedProto === 'https'
|| $forwardedSsl === 'on'
);
}
function remember_me_lifetime(): int
{
return 60 * 60 * 24 * 30;
}
function session_cookie_params_for(int $lifetime = 0): array
{
return [
'lifetime' => $lifetime,
'path' => '/',
'domain' => '',
'secure' => request_is_secure(),
'httponly' => true,
'samesite' => 'Lax',
];
}
function session_cookie_options_for(int $expires = 0): array
{
return [
'expires' => $expires,
'path' => '/',
'domain' => '',
'secure' => request_is_secure(),
'httponly' => true,
'samesite' => 'Lax',
];
}
function sport_icon_path(string $icon): string
{
return icon_path('sport-' . $icon);
@@ -184,11 +225,18 @@ function sport_icon_path(string $icon): string
function sport_icon_options(): array
{
return [
'strength-home' => 'Kraftsport daheim',
'strength-gym' => 'Kraftsport im Gym',
'strength' => 'Krafttraining',
'bike' => 'Radfahren',
'run' => 'Joggen',
'hike' => 'Wandern',
'swim' => 'Schwimmen',
'yoga' => 'Yoga',
'hiit' => 'HIIT / Workout',
'row' => 'Rudergerät',
'dance' => 'Tanzen',
'core' => 'Core',
'strength-home' => 'Krafttraining Zuhause',
'strength-gym' => 'Krafttraining Auswärts',
];
}