From b9bb620ae01134431ff1941e7577ba58eee84e42 Mon Sep 17 00:00:00 2001 From: Josh Ashton Date: Mon, 31 Mar 2025 23:39:40 -0600 Subject: [PATCH] implemented secure remember me functionality --- composer.json | 3 ++- functions/account_functions.php | 27 +++++++++++++++++++-------- functions/init.php | 18 ++++++++++++++++++ scripts/init.sql | 9 +++++++++ user.php | 2 +- 5 files changed, 49 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 53a1387..4aa7cf4 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,8 @@ "type": "project", "require": { "erusev/parsedown": "^1.7", - "vlucas/phpdotenv": "^5.6" + "vlucas/phpdotenv": "^5.6", + "phpmailer/phpmailer": "^6.9" }, "authors": [ { diff --git a/functions/account_functions.php b/functions/account_functions.php index 583927d..2be1508 100644 --- a/functions/account_functions.php +++ b/functions/account_functions.php @@ -41,7 +41,6 @@ function cookies($user, $time) function logout() { foreach (array_keys($_COOKIE) as $key) { - echo 'unsetting ' . $key . ' now.'; setcookie($key, '', time() - 3600, '/'); unset($_COOKIE[$key]); } @@ -93,13 +92,19 @@ function login($username, $password, $stay_logged_in) return $error_msg; } - if ($stay_logged_in) - $time = time() + 60 * 60 * 24 * 365; - else - $time = time() + 60 * 60 * 24 * 1; - + $time = time() + 60 * 60 * 1; cookies($user, $time); + if ($stay_logged_in) { + $token = bin2hex(random_bytes(64)); + // echo $token . '
'; + // echo strlen($token); + setcookie('remember_user', $token, time() + 60 * 60 * 24 * 30, '/', '', true, true); + + $stmt = 'INSERT INTO remember_user (token, user_id, remote_addr' . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? ', http_forward' : '') . ') VALUES ("' . $token . '", ' . $user['user_id'] . ', "' . hash('sha256', $_SERVER['REMOTE_ADDR']) . '"' . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? ', "' . hash('sha256', $_SERVER['HTTP_X_FORWARDED_FOR']) . '"' : '') . ');'; + exec_statement($stmt, 1); + } + return true; } @@ -439,7 +444,10 @@ function delete_account($user_id, $password = null, $verify_password = null) return $error_msg; } - delete_file($_ENV['PROFILE_IMAGES_FQ_PATH'] . $user['profile_picture']); + // Hardcoded prevention of deleting the owner's profile picture + if ($user['profile_picture'] != '2025.jpg') + delete_file($_ENV['PROFILE_IMAGES_FQ_PATH'] . $user['profile_picture']); + $stmt = 'DELETE FROM user WHERE user_id = ' . $user_id . ';'; exec_statement($stmt, 1); logout(); @@ -457,7 +465,10 @@ function delete_account($user_id, $password = null, $verify_password = null) return $error_msg; } - delete_file($_ENV['PROFILE_IMAGES_FQ_PATH'] . $user['profile_picture']); + // Hardcoded prevention of deleting the owner's profile picture + if ($user['profile_picture'] != '2025.jpg') + delete_file($_ENV['PROFILE_IMAGES_FQ_PATH'] . $user['profile_picture']); + $stmt = 'DELETE FROM user WHERE user_id = ' . $user_id . ';'; exec_statement($stmt, 1); } diff --git a/functions/init.php b/functions/init.php index eb46387..3f17eb5 100644 --- a/functions/init.php +++ b/functions/init.php @@ -4,6 +4,7 @@ session_start(); // Initialize Composer. require_once 'vendor/autoload.php'; require_once 'db_functions.php'; +require_once 'account_functions.php'; // Load environment variables. $dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../'); @@ -20,7 +21,24 @@ if ($_SESSION['initialized'] && isset($_POST['theme'])) { unset($_POST['theme']); } +// Update the database and cookies to keep the user logged in. if (isset($_COOKIE['user_id'])) { exec_statement('UPDATE user SET is_active = true WHERE user_id = ' . $_COOKIE['user_id'] . ';', 1); exec_statement('UPDATE user SET last_active = CURRENT_TIMESTAMP WHERE user_id = ' . $_COOKIE['user_id'] . ';', 1); + + $query = 'SELECT user_id, username, email, role_id, profile_picture FROM user WHERE user_id = ' . $_COOKIE['user_id'] . ';'; + $user = query_one_result($query); + $time = time() + 60 * 60 * 1; + cookies($user, $time); +} else if (isset($_COOKIE['remember_user'])) { + $query = 'SELECT * FROM remember_user WHERE token = "' . $_COOKIE['remember_user'] . '";'; + $remember = query_one_result($query); + $query = 'SELECT user_id, username, email, role_id, profile_picture FROM user WHERE user_id = ' . $remember['user_id'] . ';'; + $user = query_one_result($query); + + exec_statement('UPDATE user SET is_active = true WHERE user_id = ' . $user['user_id'] . ';', 1); + exec_statement('UPDATE user SET last_active = CURRENT_TIMESTAMP WHERE user_id = ' . $user['user_id'] . ';', 1); + + $time = time() + 60 * 60 * 1; + cookies($user, $time); } diff --git a/scripts/init.sql b/scripts/init.sql index 86fc115..e9c84b1 100644 --- a/scripts/init.sql +++ b/scripts/init.sql @@ -24,6 +24,15 @@ CREATE TABLE user ( FOREIGN KEY (role_id) REFERENCES roles (role_id) ); +CREATE TABLE remember_user ( + token VARCHAR(128) PRIMARY KEY, + user_id INT NOT NULL, + remote_addr VARCHAR(64) NOT NULL, + http_forward VARCHAR(64), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES user (user_id) +); + CREATE TABLE article ( article_id INT PRIMARY KEY AUTO_INCREMENT, author_id INT NOT NULL, diff --git a/user.php b/user.php index 2836eb0..cdc88dd 100644 --- a/user.php +++ b/user.php @@ -33,7 +33,7 @@ if (isset($_POST['form_id'])) { $msg = login( $_POST['username'], $_POST['password'], - (isset($POST['stay_logged_in']) ? true : false) + (isset($_POST['stay_logged_in']) ? true : false) ); if ($msg === true)