diff options
| -rwxr-xr-x | css/desktop/checkbox.css | 22 | ||||
| -rwxr-xr-x | css/desktop/login.css | 5 | ||||
| -rwxr-xr-x | css/desktop/navbar.css | 5 | ||||
| -rwxr-xr-x | html/account.html | 19 | ||||
| -rwxr-xr-x | html/guest.html | 20 | ||||
| -rwxr-xr-x | html/navbar.html | 3 | ||||
| -rwxr-xr-x | html/stylesheets.html | 1 | ||||
| -rwxr-xr-x | php/header.php | 15 | ||||
| -rwxr-xr-x | php/session.php | 71 | ||||
| -rwxr-xr-x | signin/content.html | 20 | ||||
| -rwxr-xr-x | signin/signin.php | 57 |
11 files changed, 227 insertions, 11 deletions
diff --git a/css/desktop/checkbox.css b/css/desktop/checkbox.css new file mode 100755 index 0000000..5de1d8c --- /dev/null +++ b/css/desktop/checkbox.css @@ -0,0 +1,22 @@ +/* + * GNUfault.org - GNUfault's website + * Copyright (C) 2026 Connor Thomson + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +.checkbox { + margin: 0; + accent-color: #12A3EB; +} diff --git a/css/desktop/login.css b/css/desktop/login.css index 257924a..46eda9e 100755 --- a/css/desktop/login.css +++ b/css/desktop/login.css @@ -42,3 +42,8 @@ grid-column: 2; justify-self: center; } + +.login .group .checkbox { + width: auto; + justify-self: start; +} diff --git a/css/desktop/navbar.css b/css/desktop/navbar.css index 62f174c..4c8f813 100755 --- a/css/desktop/navbar.css +++ b/css/desktop/navbar.css @@ -35,3 +35,8 @@ .header .navbar a:hover { text-decoration: underline; } + +.header .navbar .username { + margin: 3px; + font-weight: bold; +} diff --git a/html/account.html b/html/account.html new file mode 100755 index 0000000..cad5558 --- /dev/null +++ b/html/account.html @@ -0,0 +1,19 @@ +<!-- + GNUfault.org - GNUfault's website + Copyright (C) 2026 Connor Thomson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +--> + +<span class="username">{{username}}</span> diff --git a/html/guest.html b/html/guest.html new file mode 100755 index 0000000..c37d3fa --- /dev/null +++ b/html/guest.html @@ -0,0 +1,20 @@ +<!-- + GNUfault.org - GNUfault's website + Copyright (C) 2026 Connor Thomson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +--> + +<a href="/signup">Sign-up</a> +<a href="/signin">Sign-in</a> diff --git a/html/navbar.html b/html/navbar.html index e2869b7..6d7596c 100755 --- a/html/navbar.html +++ b/html/navbar.html @@ -20,6 +20,5 @@ <a href="/">Home</a> </div> <div> - <a href="/signup">Sign-up</a> - <a href="/signin">Sign-in</a> + {{account}} </div> diff --git a/html/stylesheets.html b/html/stylesheets.html index e458dfe..4e3852c 100755 --- a/html/stylesheets.html +++ b/html/stylesheets.html @@ -22,6 +22,7 @@ <link rel="stylesheet" href="/css/{{device}}/footer.css"> <link rel="stylesheet" href="/css/{{device}}/container.css"> <link rel="stylesheet" href="/css/{{device}}/button.css"> +<link rel="stylesheet" href="/css/{{device}}/checkbox.css"> <link rel="stylesheet" href="/css/{{device}}/input.css"> <link rel="stylesheet" href="/css/{{device}}/login.css"> <link rel="stylesheet" href="/css/{{device}}/navbar.css"> diff --git a/php/header.php b/php/header.php index 3f7279b..8648b2a 100755 --- a/php/header.php +++ b/php/header.php @@ -18,9 +18,22 @@ */ require_once ROOT . '/php/replace.php'; +require_once ROOT . '/php/session.php'; + +$username = get_username(); + +if ($username === null) { + $account = import(ROOT . '/html/guest.html'); +} else { + $account = replace(ROOT . '/html/account.html', [ + '{{username}}' => htmlspecialchars($username, ENT_QUOTES, 'UTF-8') + ]); +} $targets = [ - '{{navbar}}' => import(ROOT . '/html/navbar.html') + '{{navbar}}' => replace(ROOT . '/html/navbar.html', [ + '{{account}}' => $account + ]) ]; $html = replace(ROOT . '/html/header.html', $targets); diff --git a/php/session.php b/php/session.php index 7895dfb..acb2df3 100755 --- a/php/session.php +++ b/php/session.php @@ -17,20 +17,63 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -function start_session(): void { - if (session_status() === PHP_SESSION_ACTIVE) { - return; - } +const SESSION_LIFETIME = 60 * 60 * 24 * 365; - session_set_cookie_params([ - 'lifetime' => 0, +function session_cookie(int $lifetime): array { + return [ + 'lifetime' => $lifetime, 'path' => '/', 'secure' => true, 'httponly' => true, 'samesite' => 'Strict' - ]); + ]; +} + +function has_session(): bool { + if (session_status() === PHP_SESSION_ACTIVE) { + return true; + } + + return isset($_COOKIE[session_name()]); +} + +function start_session(): void { + if (session_status() === PHP_SESSION_ACTIVE) { + return; + } + + ini_set('session.gc_maxlifetime', (string)SESSION_LIFETIME); + + session_set_cookie_params(session_cookie(0)); session_start(); + + if (!empty($_SESSION['remember'])) { + remember_session(); + } +} + +function remember_session(): void { + $parameters = session_cookie(SESSION_LIFETIME); + $parameters['expires'] = time() + $parameters['lifetime']; + + unset($parameters['lifetime']); + + setcookie(session_name(), session_id(), $parameters); +} + +function sign_in(int $user_id, string $username, bool $remember): void { + start_session(); + + session_regenerate_id(true); + + $_SESSION['user_id'] = $user_id; + $_SESSION['username'] = $username; + $_SESSION['remember'] = $remember; + + if ($remember) { + remember_session(); + } } function set_user_id(int $user_id): void { @@ -42,9 +85,23 @@ function set_user_id(int $user_id): void { } function get_user_id(): ?int { + if (!has_session()) { + return null; + } + start_session(); return isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null; } +function get_username(): ?string { + if (!has_session()) { + return null; + } + + start_session(); + + return isset($_SESSION['username']) ? (string)$_SESSION['username'] : null; +} + ?> diff --git a/signin/content.html b/signin/content.html index 458ecfb..ac9eb13 100755 --- a/signin/content.html +++ b/signin/content.html @@ -16,4 +16,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. --> -<p>WIP</p> +<h2>Sign in to GNUfault.org</h2> +<hr> +<p>If you need any help, email me at <<a href="mailto:noreply@gnufault.org">connor@gnufault.org</a>>.</p> +<br> +<form class="login" action="signin.php" method="POST"> + <div class="group"> + <label for="username">Username:</label> + <input class="input" type="text" id="username" name="username" required> + </div> + <div class="group"> + <label for="password">Password:</label> + <input class="input" type="password" id="password" name="password" required> + </div> + <div class="group"> + <label for="remember">Remember me:</label> + <input class="checkbox" type="checkbox" id="remember" name="remember" checked> + </div> + <button class="button" type="submit">Send</button> +</form> diff --git a/signin/signin.php b/signin/signin.php new file mode 100755 index 0000000..6e88336 --- /dev/null +++ b/signin/signin.php @@ -0,0 +1,57 @@ +<?php +/* + * GNUfault.org - GNUfault's website + * Copyright (C) 2026 Connor Thomson + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +define('ROOT', rtrim($_SERVER['DOCUMENT_ROOT'], '/') . '/'); + +require_once ROOT . '/php/session.php'; +require_once ROOT . '/php/database.php'; + +if ($_SERVER["REQUEST_METHOD"] == "POST") { + $username = $_POST['username']; + $password = $_POST['password']; + $remember = isset($_POST['remember']); + + try { + $sql = "SELECT id, username, password, verification_code FROM users WHERE username = :username"; + + $user = fetch_row($sql, ['username' => $username]); + } catch (\PDOException $e) { + echo "Error: " . $e->getMessage(); + exit; + } + + // The same message either way, so it does not say which usernames exist + if (!$user || !password_verify($password, $user['password'])) { + echo "Username or password is not correct!"; + exit; + } + + if ($user['verification_code'] != '0001') { + set_user_id((int)$user['id']); + + header("Location: /signup/verify"); + exit; + } + + sign_in((int)$user['id'], $user['username'], $remember); + + header("Location: /"); +} + +?> |
