fix: not being able to stay logged in

This commit is contained in:
grandeljay 2023-11-24 18:23:13 +01:00
parent 01ad3b6a58
commit 0b87dc3cac
4 changed files with 215 additions and 37 deletions

View file

@ -33,19 +33,6 @@ spl_autoload_register(
} }
); );
/**
* Session
*
* Has to be setup first, before anything else, so translations can be loaded.
*/
session_start(
array(
'name' => 'wishthis',
)
);
$user = User::getCurrent();
/** /**
* Config * Config
*/ */
@ -55,6 +42,22 @@ if (file_exists($configPath)) {
require $configPath; require $configPath;
} }
/**
* Session
*
* Has to be setup first, before anything else, so translations can be loaded.
* The configuration is the only exception, since `loadFromSession` needs the
* database.
*/
session_start(
array(
'name' => 'wishthis',
'cookie_lifetime' => \ini_get('session.gc_maxlifetime') ?: 1440,
)
);
$user = User::getCurrent();
$user->loadFromSession();
/** /**
* Database * Database

View file

@ -160,6 +160,10 @@ class Page
*/ */
$user = User::getCurrent(); $user = User::getCurrent();
if ($user->isLoggedIn()) {
$user->refreshSession();
}
/** /**
* Login * Login
*/ */

View file

@ -45,9 +45,7 @@ class User
$_SESSION['user'] = new self(); $_SESSION['user'] = new self();
} }
$user = $_SESSION['user']; return $_SESSION['user'];
return $user;
} }
/** /**
@ -159,6 +157,13 @@ class User
*/ */
private bool $advertisements = false; private bool $advertisements = false;
/**
* Whether the user wants to stay logged in.
*
* @var bool
*/
private bool $stayLoggedIn = false;
/** /**
* Non-Static * Non-Static
*/ */
@ -244,7 +249,38 @@ class User
*/ */
public function isLoggedIn(): bool public function isLoggedIn(): bool
{ {
return isset($this->id) && $this->id >= 1; if (!isset($_COOKIE['wishthis'])) {
return false;
}
$database = new Database(
DATABASE_HOST,
DATABASE_NAME,
DATABASE_USER,
DATABASE_PASSWORD
);
$database->connect();
$session = $database
->query(
'SELECT *
FROM `sessions`
WHERE `session` = :session',
array(
'session' => $_COOKIE['wishthis'],
)
)
->fetch();
if (false === $session) {
return false;
}
if (\strtotime($session['expires']) <= \time()) {
return false;
}
return true;
} }
/** /**
@ -313,7 +349,7 @@ class User
* *
* @return bool Whether the log in was successful. * @return bool Whether the log in was successful.
*/ */
public function logIn(string $email = '', string $password = '', bool $user_login_is_persistent = false): bool public function logIn(string $email = '', string $password = '', bool $userLoginIsPersistent = false): bool
{ {
$database = new Database( $database = new Database(
DATABASE_HOST, DATABASE_HOST,
@ -344,7 +380,7 @@ class User
'user_password' => $password, 'user_password' => $password,
) )
) )
->fetch(); ->fetch(\PDO::FETCH_ASSOC);
/** /**
* Fetching the user fields has failed and we are now assuming that the * Fetching the user fields has failed and we are now assuming that the
@ -368,30 +404,19 @@ class User
'user_password' => $password, 'user_password' => $password,
) )
); );
$user_database_fields['last_login'] = time(); $user_database_fields['last_login'] = date('Y-m-d H:i');
/** /**
* Set session duration * Set session duration
*/ */
$database $this->refreshSession($user_database_fields['id']);
->query(
'REPLACE INTO `sessions` (`user`, `session`, `expires`) VALUES (
:user_id,
:session_id,
:session_expires
)',
array(
'user_id' => $user_database_fields['id'],
'session_id' => \session_id(),
'session_expires' => date('Y-m-d H:i', time() + 1800),
)
);
/** /**
* Create a `User` object instance and assign it for later use. * Create a `User` object instance and assign it for later use.
*/ */
if (\is_array($user_database_fields)) { if (\is_array($user_database_fields)) {
$this->__construct($user_database_fields); $this->__construct($user_database_fields);
$this->stayLoggedIn = $userLoginIsPersistent;
$_SESSION['user'] = $this; $_SESSION['user'] = $this;
@ -404,6 +429,22 @@ class User
public function logOut(): void public function logOut(): void
{ {
/** Destroy session */ /** Destroy session */
$database = new Database(
DATABASE_HOST,
DATABASE_NAME,
DATABASE_USER,
DATABASE_PASSWORD
);
$database->connect();
$database
->query(
'DELETE FROM `sessions`
WHERE `session` = :session',
array(
'session' => $_COOKIE['wishthis'],
)
);
session_destroy(); session_destroy();
unset($_SESSION); unset($_SESSION);
} }
@ -510,4 +551,133 @@ class User
{ {
return $this->password_reset_valid_until; return $this->password_reset_valid_until;
} }
public function refreshSession(int $forUser = 0): void
{
$sessionId = $_COOKIE['wishthis'];
$sessionDurationSeconds = \ini_get('session.gc_maxlifetime') ?: 1440;
if ($this->stayLoggedIn) {
$sessionDurationSeconds = 31104000; // One year
}
if (0 === $forUser) {
$forUser = $this->id;
}
$database = new Database(
DATABASE_HOST,
DATABASE_NAME,
DATABASE_USER,
DATABASE_PASSWORD
);
$database->connect();
/** Delete outdated sessions */
$database
->query(
'DELETE FROM `sessions`
WHERE `expires` <= NOW()',
);
/** Find existing session */
$sessionsExisting = $database
->query(
'SELECT *
FROM `sessions`
WHERE `session` = :session',
array(
'session' => $sessionId,
)
)
->fetchAll();
/** The session exists and can be updated now */
foreach ($sessionsExisting as $session) {
if ($session['session'] === $sessionId) {
$database
->query(
'UPDATE `sessions`
SET `expires` = :expires
WHERE `session` = :session
AND `user` = :user',
array(
'expires' => date('Y-m-d H:i', time() + $sessionDurationSeconds),
'session' => $sessionId,
'user' => $forUser,
)
);
/** There's no need to do anything further. */
return;
}
}
/**
* Since there has been no return until now, we are assuming the session
* does not exist and will create it now.
*/
$database
->query(
'INSERT INTO `sessions` (`user`, `session`, `expires`) VALUES (
:user_id,
:session_id,
:session_expires
)',
array(
'user_id' => $forUser,
'session_id' => $sessionId,
'session_expires' => date('Y-m-d H:i', time() + $sessionDurationSeconds),
)
);
}
public function loadFromSession(): void
{
if (!$this->isLoggedIn()) {
return;
}
$database = new Database(
DATABASE_HOST,
DATABASE_NAME,
DATABASE_USER,
DATABASE_PASSWORD
);
$database->connect();
$session = $database
->query(
'SELECT *
FROM `sessions`
WHERE `session` = :session
AND `user` = :user',
array(
'session' => $_COOKIE['wishthis'],
'user' => $this->id,
)
)
->fetch(\PDO::FETCH_ASSOC);
if (false === $session) {
return;
}
$user = $database
->query(
'SELECT *
FROM `users`
WHERE `id` = :user',
array(
'user' => $this->id,
)
)
->fetch(\PDO::FETCH_ASSOC);
if (false === $user) {
return;
}
$this->__construct($user);
}
} }

View file

@ -16,9 +16,10 @@ $page = new Page(__FILE__, __('Login'));
if (isset($_POST['login'], $_POST['email'], $_POST['password'])) { if (isset($_POST['login'], $_POST['email'], $_POST['password'])) {
$user_email = \filter_input(\INPUT_POST, 'email', FILTER_SANITIZE_EMAIL); $user_email = \filter_input(\INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$user_password = User::passwordToHash($_POST['password']); $user_password = User::passwordToHash($_POST['password']);
$user_login_is_persistent = isset($_POST['persistent']); $userLoginIsPersistent = isset($_POST['persistent']);
$user->login($user_email, $user_password, $user_login_is_persistent); $user->login($user_email, $user_password, $userLoginIsPersistent);
$user = User::getCurrent();
if (!$user->isLoggedIn()) { if (!$user->isLoggedIn()) {
$page->messages[] = Page::error( $page->messages[] = Page::error(