From 7cc2534f9183bb3116b19ffca52789f1f50900f7 Mon Sep 17 00:00:00 2001 From: ilotterytea Date: Tue, 6 May 2025 00:56:04 +0500 Subject: feat: account registration and login --- public/account/index.php | 4 +- public/account/login/index.php | 80 ++++++++++++++++++++++++----- public/account/login/twitch.php | 2 +- public/account/register.php | 111 ++++++++++++++++++++++++++++++++++++++++ public/static/style.css | 7 +++ src/config.sample.php | 5 +- 6 files changed, 191 insertions(+), 18 deletions(-) create mode 100644 public/account/register.php diff --git a/public/account/index.php b/public/account/index.php index ff0b745..8ecce33 100644 --- a/public/account/index.php +++ b/public/account/index.php @@ -16,7 +16,7 @@ if (!isset($_SESSION["user_id"], $_SESSION["user_name"])) { if ($_SERVER['REQUEST_METHOD'] == "POST") { $db = new PDO(DB_URL, DB_USER, DB_PASS); - $username = str_safe($_POST["username"] ?? "", ACCOUNT_USERNAME_MAX_LENGTH); + $username = str_safe($_POST["username"] ?? "", ACCOUNT_USERNAME_LENGTH[1]); if (!empty($username) && $username != $_SESSION["user_name"]) { if (!preg_match(ACCOUNT_USERNAME_REGEX, $username)) { @@ -126,7 +126,7 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") { username.addEventListener("input", (e) => { const regex = ; - if (regex.test(e.target.value) && e.target.value.length <= ) { + if (regex.test(e.target.value) && e.target.value.length <= ) { validUsername = e.target.value; } else { e.target.value = validUsername; diff --git a/public/account/login/index.php b/public/account/login/index.php index 4eb37ae..7c562d1 100644 --- a/public/account/login/index.php +++ b/public/account/login/index.php @@ -1,16 +1,44 @@ prepare("SELECT secret_key, password FROM users WHERE username = ? AND password IS NOT NULL"); + $stmt->execute([$username]); + + if ($row = $stmt->fetch()) { + if (password_verify($password, $row["password"])) { + setcookie("secret_key", $row["secret_key"], $remember ? (time() + ACCOUNT_COOKIE_MAX_LIFETIME) : 0, "/"); + header("Location: /account"); + exit; + } else { + generate_alert("/account/login", "Passwords do not match!", 403); + exit; + } + } else { + generate_alert("/account/login", "User not found or is not accessable", 404); + exit; + } +} ?> @@ -25,21 +53,45 @@ if (!ACCOUNT_REGISTRATION_ENABLE) {
- -
-
+
+ +
- -
- -
- +
+
+ + +
+
+ + +
+
+ + +
+
+ + + Register + +
+
+ + +
+ Login with Twitch +

Logging in via Twitch gives you the ability to use + emotes in your Twitch chat. +

+
+
diff --git a/public/account/login/twitch.php b/public/account/login/twitch.php index 05093cd..e3fe57a 100644 --- a/public/account/login/twitch.php +++ b/public/account/login/twitch.php @@ -129,7 +129,7 @@ if ($row = $stmt->fetch()) { $_SESSION["user_id"] = $user_id; $_SESSION["user_name"] = $user_name; -setcookie("secret_key", $user_secret_key, time() + 86400 * 30, "/"); +setcookie("secret_key", $user_secret_key, time() + ACCOUNT_COOKIE_MAX_LIFETIME, "/"); $db = null; diff --git a/public/account/register.php b/public/account/register.php new file mode 100644 index 0000000..1da89a0 --- /dev/null +++ b/public/account/register.php @@ -0,0 +1,111 @@ + $username_length || $username_length > ACCOUNT_USERNAME_LENGTH[1]) { + generate_alert("/account/register.php", sprintf("Username must be between %d-%d characters long", ACCOUNT_USERNAME_LENGTH[0], ACCOUNT_USERNAME_LENGTH[1])); + exit; + } + + if (!preg_match(ACCOUNT_USERNAME_REGEX, $username)) { + generate_alert("/account/register.php", "Bad username"); + exit; + } + + $password = $_POST["password"]; + if (ACCOUNT_PASSWORD_MIN_LENGTH > strlen($password)) { + generate_alert("/account/register.php", "Password must be at least " . ACCOUNT_PASSWORD_MIN_LENGTH . " characters"); + exit; + } + + $db = new PDO(DB_URL, DB_USER, DB_PASS); + + $stmt = $db->prepare("SELECT id FROM users WHERE username = ?"); + $stmt->execute([$username]); + + if ($stmt->rowCount() != 0) { + generate_alert("/account/register.php", "The username has already been taken"); + exit; + } + + $secret_key = generate_random_string(ACCOUNT_SECRET_KEY_LENGTH); + $password = password_hash($password, PASSWORD_DEFAULT); + + $id = bin2hex(random_bytes(16)); + + $stmt = $db->prepare("INSERT INTO users(id, username, password, secret_key) VALUES (?, ?, ?, ?)"); + $stmt->execute([$id, $username, $password, $secret_key]); + + setcookie("secret_key", $secret_key, time() + ACCOUNT_COOKIE_MAX_LIFETIME, "/"); + header("Location: /account"); + exit; +} +?> + + + + + Register an account - <?php echo INSTANCE_NAME ?> + + + + + +
+
+ + +
+ +
+ +
+
+
+ + +
+
+ + +
+
+ +
+
+

+ Since doesn't require email and password reset via email is + not supported, please remember your passwords! +

+
+
+
+
+
+ + + \ No newline at end of file diff --git a/public/static/style.css b/public/static/style.css index 06be5e1..ed1396c 100644 --- a/public/static/style.css +++ b/public/static/style.css @@ -73,6 +73,13 @@ form { gap: 4px; } +label { + display: block; +} + +label.inline { + display: inline; +} .container { width: 100%; diff --git a/src/config.sample.php b/src/config.sample.php index f1c3a45..3181956 100644 --- a/src/config.sample.php +++ b/src/config.sample.php @@ -38,8 +38,11 @@ define("REPORTS_ENABLE", true); // Enable emote, user reports. // ACCOUNTS define("ACCOUNT_REGISTRATION_ENABLE", true); // Enable account registration. +define("ACCOUNT_COOKIE_MAX_LIFETIME", 86400 * 30); // Remember user for a month. define("ACCOUNT_USERNAME_REGEX", "/^[A-Za-z0-9_]+$/"); // RegEx filter for account usernames. -define("ACCOUNT_USERNAME_MAX_LENGTH", 20); // Max length for account usernames. +define("ACCOUNT_USERNAME_LENGTH", [2, 20]); // [Min, Max] length for account usernames. +define("ACCOUNT_PASSWORD_MIN_LENGTH", 10); // Minimal length for passwords. +define("ACCOUNT_SECRET_KEY_LENGTH", 32); // The length for secret keys. define("ACCOUNT_PFP_MAX_SIZE", [128, 128]); // Max dimensions for account pictures. define("ACCOUNT_BANNER_MAX_SIZE", [1920, 1080]); // Max dimensions for account banners. -- cgit v1.2.3