summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConnor Thomson <blumatrikz@gmail.com>2026-09-20 18:59:16 -0700
committerConnor Thomson <blumatrikz@gmail.com>2026-09-20 18:59:48 -0700
commit81c04315ee022a044c8d22ae7a9bbe065e21f2df (patch)
treebd3fed9001a07917c0f45b6f51e62fffc1ea2c97
parent09cda8862f59f25918c64477d829e46acfc676cb (diff)
Add signin
-rwxr-xr-xcss/desktop/checkbox.css22
-rwxr-xr-xcss/desktop/login.css5
-rwxr-xr-xcss/desktop/navbar.css5
-rwxr-xr-xhtml/account.html19
-rwxr-xr-xhtml/guest.html20
-rwxr-xr-xhtml/navbar.html3
-rwxr-xr-xhtml/stylesheets.html1
-rwxr-xr-xphp/header.php15
-rwxr-xr-xphp/session.php71
-rwxr-xr-xsignin/content.html20
-rwxr-xr-xsignin/signin.php57
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 &lt;<a href="mailto:noreply@gnufault.org">connor@gnufault.org</a>&gt;.</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: /");
+}
+
+?>