diff --git a/assets/login-script.js b/assets/login-script.js
index afced83..e6438ac 100644
--- a/assets/login-script.js
+++ b/assets/login-script.js
@@ -1,6 +1,6 @@
function login() {
- var email = document.getElementById("email").value;
- var password = document.getElementById("password").value;
+ const email = document.getElementById("email").value;
+ const password = document.getElementById("password").value;
// Assuming you use fetch API to send data to the server
fetch('https://home.adlerka.top/account', {
diff --git a/endpoints/global/account.php b/endpoints/global/account.php
index b876429..1604f3f 100644
--- a/endpoints/global/account.php
+++ b/endpoints/global/account.php
@@ -2,18 +2,35 @@
require_once "lib/account.php";
-function endpoint($endpoint_data)
+function endpoint($endpoint_data): array
{
- switch ($endpoint_data["action"]){
-
- case "login":
- return doLogin($endpoint_data["email"], $endpoint_data["password"]);
-
- case "logout":
- return doLogout();
-
- case "register":
- return doRegister($endpoint_data["firstname"], $endpoint_data["lastname"], $endpoint_data["nickname"], $endpoint_data["email"], $endpoint_data["password"], $endpoint_data["minecraftnick"], $endpoint_data["activation_token"]);
-
- }
-}
\ No newline at end of file
+ return match ($endpoint_data["action"]) {
+ "login" => doLogin($endpoint_data["email"], $endpoint_data["password"]),
+ "logout" => doLogout(),
+ "register" => doRegister(
+ $endpoint_data["firstname"],
+ $endpoint_data["lastname"],
+ $endpoint_data["nickname"],
+ $endpoint_data["email"],
+ $endpoint_data["password"],
+ $endpoint_data["minecraftnick"],
+ $endpoint_data["activation_token"]
+ ),
+ "change_password" => changePassword($endpoint_data["user_id"], $endpoint_data["new_password"]),
+ "update_user_profile" => updateUserProfile(
+ $endpoint_data["user_id"],
+ $endpoint_data["first_name"],
+ $endpoint_data["last_name"],
+ $endpoint_data["nickname"],
+ $endpoint_data["minecraft_nick"]
+ ),
+ "get_user_info" => getUserInfo($endpoint_data["user_id"]),
+ "is_email_available" => isEmailAvailable($endpoint_data["email"]),
+ "add_activation_codes" => addActivationCodes($endpoint_data["count"]),
+ "list_users" => listUsers(),
+ "list_activation_codes" => listActivationCodes(),
+ "delete_user" => deleteUser($endpoint_data["user_id"]),
+ "delete_activation_code" => deleteActivationCode($endpoint_data["activation_code"]),
+ default => ["status" => "fail", "message" => "Invalid action"],
+ };
+}
diff --git a/index.php b/index.php
index 30c22fd..3a03525 100644
--- a/index.php
+++ b/index.php
@@ -16,7 +16,7 @@ if(initRouter()) {
session_set_cookie_params(0, '/', "." . $routerRequest["domain"] . "." . $routerRequest["tld"], true, true);
session_start();
if($routerRequest["type"] == "api") {
- echo getEndpoint($routerRequest["page_name"], $_REQUEST);
+ echo getEndpoint($routerRequest["page_name"]);
}elseif ($routerRequest["type"] == "page") {
/** @noinspection PhpArrayIsAlwaysEmptyInspection */
diff --git a/lib/account.php b/lib/account.php
index 3f9bdda..074d67e 100644
--- a/lib/account.php
+++ b/lib/account.php
@@ -1,14 +1,41 @@
0 && !empty($_SESSION["email"]);
+use Random\RandomException;
+
+function isLoggedIn(): bool
+{
+ global $routerConfig;
+ return $_SESSION["ID"] > 0 && !empty($_SESSION["email"]) && $_SESSION["privilegelevel"] >= $routerConfig["logged_in_default_permission_level"];
}
-function doLogin($email, $password){
+function generateActivationToken(): string
+{
+ try {
+ return bin2hex(random_bytes(16));
+ } catch (RandomException $e) {
+ return "error_generating_code_because_of_$e";
+ } // Adjust the length of the token as needed
+}
+function verifyPassword($userID, $password): bool
+{
global $mysqli;
+ $stmt = $mysqli->prepare("SELECT PasswordHash FROM Users WHERE ID = ?");
+ $stmt->bind_param("i", $userID);
+ $stmt->execute();
+ $pwdhash = "";
+ $stmt->bind_result($pwdhash);
+ $stmt->fetch();
+ $stmt->close();
+
+ return !empty($pwdhash) && password_verify($password, $pwdhash);
+}
+
+function doLogin($email, $password): array
+{
+ global $mysqli, $routerConfig;
$found = false;
- if(!empty($email) && !empty($password)){
- $stmt = $mysqli->prepare("SELECT ID, FirstName, LastName, Nickname, PasswordHash, MinecraftNick, PrivilegeLevel FROM Users WHERE EMAIL = ? AND isActive = 1");
+ if (!empty($email) && !empty($password)) {
+ $stmt = $mysqli->prepare("SELECT ID, FirstName, LastName, Nickname, PasswordHash, MinecraftNick, PrivilegeLevel, LastLoginAt, LoginCount FROM Users WHERE Email = ? AND isActivated = 1");
$stmt->bind_param("s", $email);
$stmt->execute();
@@ -19,31 +46,37 @@ function doLogin($email, $password){
$pwdhash = "";
$mcnick = "";
$privilegelevel = 0;
- $stmt->bind_result($idcko, $fname, $lname, $nickname, $pwdhash, $mcnick, $privilegelevel);
+ $lastLoginAt = null;
+ $loginCount = 0;
+ $stmt->bind_result($idcko, $fname, $lname, $nickname, $pwdhash, $mcnick, $privilegelevel, $lastLoginAt, $loginCount);
- if($stmt->num_rows() > 0){
+ if ($stmt->num_rows() > 0) {
$stmt->fetch();
- if (password_verify($password, $pwdhash)){
- $_SESSION["ID"] = $idcko;
- $_SESSION["first_name"] = $fname;
- $_SESSION["last_name"] = $lname;
- $_SESSION["nickname"] = $nickname;
- $_SESSION["email"] = $email;
- $_SESSION["mcnick"] = $mcnick;
- $_SESSION["privilegelevel"] = $privilegelevel;
+ if (password_verify($password, $pwdhash) && $privilegelevel >= $routerConfig["logged_in_default_permission_level"]) {
$found = true;
+
+ // Update LastLoginAt and LoginCount
+ $updateLoginStmt = $mysqli->prepare("UPDATE Users SET LastLoginAt = NOW(), LoginCount = LoginCount + 1 WHERE ID = ?");
+ $updateLoginStmt->bind_param("i", $idcko);
+ $updateLoginStmt->execute();
+ $updateLoginStmt->close();
}
}
+
+ $_SESSION["ID"] = $idcko;
+ $_SESSION["first_name"] = $fname;
+ $_SESSION["last_name"] = $lname;
+ $_SESSION["nickname"] = $nickname;
+ $_SESSION["email"] = $email;
+ $_SESSION["mcnick"] = $mcnick;
+ $_SESSION["privilegelevel"] = $privilegelevel;
$stmt->close();
}
- if (!$found){
- $_SESSION["ID"] = 0;
- $_SESSION["privilegelevel"] = 0;
- }
return $found ? ["status" => "success"] : ["status" => "fail"];
}
-function doLogout(){
+function doLogout(): array
+{
if(isLoggedIn()){
session_destroy();
return ["status" => "success"];
@@ -52,13 +85,15 @@ function doLogout(){
}
}
-function doRegister($firstname, $lastname, $nickname, $email, $password, $minecraftnick, $activationtoken){
- global $mysqli;
+function doRegister($firstname, $lastname, $nickname, $email, $password, $minecraftnick, $activationtoken): array
+{
+ global $mysqli, $routerConfig;
$status = ["status" => "fail"];
- if (!empty($activationtoken)){
+ if (!empty($activationtoken)) {
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
- $stmt = $mysqli->prepare("UPDATE Users SET FirstName = ?, LastName = ?, Nickname = ?, Email = ?, PasswordHash = ?, MinecraftNick = ?, isAdmin = 0, isActivated = 1 WHERE isActivated = 0 AND ActivationToken = ?");
- $stmt->bind_param("sssssss", $firstname, $lastname, $nickname, $email, $passwordHash, $minecraftnick, $activationtoken);
+ $stmt = $mysqli->prepare("INSERT INTO Users (FirstName, LastName, Nickname, Email, PasswordHash, MinecraftNick, PrivilegeLevel, isActivated, ActivationToken, RegisteredAt) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, NOW())");
+ $privilegelevel = $routerConfig["logged_in_default_permission_level"];
+ $stmt->bind_param("ssssssisi", $firstname, $lastname, $nickname, $email, $passwordHash, $minecraftnick, $privilegelevel, $activationtoken);
$stmt->execute();
if ($stmt->affected_rows > 0) {
$status["status"] = "success";
@@ -68,3 +103,184 @@ function doRegister($firstname, $lastname, $nickname, $email, $password, $minecr
return $status;
}
+function changePassword($userID, $newPassword): array
+{
+ global $mysqli, $routerConfig;
+ $status = ["status" => "fail"];
+ if(!empty($userID) && !empty($newPassword) && verifyPassword($userID, $newPassword) && $_SESSION["privilegelevel"] >= $routerConfig["logged_in_default_permission_level"]){
+ $passwordHash = password_hash($newPassword, PASSWORD_DEFAULT);
+ $stmt = $mysqli->prepare("UPDATE Users SET PasswordHash = ? WHERE ID = ?");
+ $stmt->bind_param("si", $passwordHash, $userID);
+ $stmt->execute();
+ if ($stmt->affected_rows > 0) {
+ $status["status"] = "success";
+ }
+ $stmt->close();
+ }
+ return $status;
+}
+
+
+function updateUserProfile($userID, $firstName, $lastName, $nickname, $minecraftNick): array
+{
+ global $mysqli;
+ $status = ["status" => "fail"];
+ if (!empty($userID)) {
+ $stmt = $mysqli->prepare("UPDATE Users SET FirstName = ?, LastName = ?, Nickname = ?, MinecraftNick = ? WHERE ID = ?");
+ $stmt->bind_param("ssssi", $firstName, $lastName, $nickname, $minecraftNick, $userID);
+ $stmt->execute();
+ if ($stmt->affected_rows > 0) {
+ $status["status"] = "success";
+ }
+ $stmt->close();
+ }
+ return $status;
+}
+
+function getUserInfo($userID): array
+{
+ global $mysqli;
+ $userInfo = [];
+ if (!empty($userID)) {
+ $stmt = $mysqli->prepare("SELECT ID, FirstName, LastName, Nickname, Email, MinecraftNick, privilegeLevel FROM Users WHERE ID = ?");
+ $stmt->bind_param("i", $userID);
+ $stmt->execute();
+ $id = 0;
+ $firstName = "";
+ $lastName = "";
+ $nickname = "";
+ $email = "";
+ $minecraftNick = "";
+ $privilegeLevel = 0;
+
+ $stmt->bind_result($id, $firstName, $lastName, $nickname, $email, $minecraftNick, $privilegeLevel);
+ $stmt->fetch();
+ $stmt->close();
+
+ $userInfo = [
+ "ID" => $id,
+ "FirstName" => $firstName,
+ "LastName" => $lastName,
+ "Nickname" => $nickname,
+ "Email" => $email,
+ "MinecraftNick" => $minecraftNick,
+ "PrivilegeLevel" => $privilegeLevel
+ ];
+ }
+ return $userInfo;
+}
+
+function isEmailAvailable($email): bool
+{
+ global $mysqli;
+ $stmt = $mysqli->prepare("SELECT COUNT(*) FROM Users WHERE Email = ?");
+ $stmt->bind_param("s", $email);
+ $stmt->execute();
+ $count = -1;
+ $stmt->bind_result($count);
+ $stmt->fetch();
+ $stmt->close();
+
+ return $count === 0;
+}
+
+
+function addActivationCodes($count): array
+{
+ global $mysqli, $routerConfig;
+ $activationCodes = [];
+
+ if (is_numeric($count) && $count > 0 && $_SESSION["privilegelevel"] >= $routerConfig["user_admin_permission_level"]) {
+ $stmt = $mysqli->prepare("UPDATE Users SET ActivationCode = ?, CreatedAt = NOW(), CreatedBy = ? WHERE ID = ?");
+
+ for ($i = 0; $i < $count; $i++) {
+ $activationCode = generateActivationToken();
+ $stmt->bind_param("sii", $activationCode, $_SESSION["ID"], $_SESSION["ID"]);
+ $stmt->execute();
+
+ if ($stmt->affected_rows > 0) {
+ $activationCodes[] = [
+ "Code" => $activationCode,
+ "CreatedAt" => date("Y-m-d H:i:s"),
+ "CreatedBy" => $_SESSION["ID"]
+ ];
+ }
+ }
+
+ $stmt->close();
+ }
+
+ return $activationCodes;
+}
+
+function listUsers(): array
+{
+ global $mysqli, $routerConfig;
+ $users = ["status" => "fail"]; // Default status is "fail"
+
+ if ($_SESSION["privilegelevel"] >= $routerConfig["user_admin_permission_level"]) {
+ $users = [];
+ $result = $mysqli->query("SELECT ID, FirstName, LastName, Nickname, Email, MinecraftNick, PrivilegeLevel, CreatedAt, RegisteredAt, LastLoginAt, LoginCount, CreatedBy FROM Users");
+
+ // Check if the query executed successfully
+ if ($result) {
+ while ($row = $result->fetch_assoc()) {
+ $users[] = $row;
+ }
+ }
+ }
+
+ return $users;
+}
+
+function listActivationCodes(): array
+{
+ global $mysqli, $routerConfig;
+ $activationCodes = ["status" => "fail"]; // Default status is "fail"
+
+ if ($_SESSION["privilegelevel"] >= $routerConfig["user_admin_permission_level"]) {
+ $activationCodes = [];
+ $result = $mysqli->query("SELECT Code, CreatedAt, CreatedBy FROM Users");
+
+ // Check if the query executed successfully
+ if ($result) {
+ while ($row = $result->fetch_assoc()) {
+ $activationCodes[] = $row;
+ }
+ }
+ }
+
+ return $activationCodes;
+}
+
+function deleteUser($userID): array
+{
+ global $mysqli, $routerConfig;
+ $status = ["status" => "fail"];
+ if (!empty($userID) && $_SESSION["privilegelevel"] >= $routerConfig["user_admin_permission_level"]) {
+ $stmt = $mysqli->prepare("DELETE FROM Users WHERE ID = ?");
+ $stmt->bind_param("i", $userID);
+ $stmt->execute();
+ if ($stmt->affected_rows > 0) {
+ $status["status"] = "success";
+ }
+ $stmt->close();
+ }
+ return $status;
+}
+
+function deleteActivationCode($activationCode): array
+{
+ global $mysqli, $routerConfig;
+ $status = ["status" => "fail"];
+ if (!empty($activationCode) && $_SESSION["privilegelevel"] >= $routerConfig["user_admin_permission_level"]) {
+ $stmt = $mysqli->prepare("DELETE FROM Users WHERE ActivationToken = ?");
+ $stmt->bind_param("s", $activationCode);
+ $stmt->execute();
+ if ($stmt->affected_rows > 0) {
+ $status["status"] = "success";
+ }
+ $stmt->close();
+ }
+ return $status;
+}
\ No newline at end of file
diff --git a/lib/config.php b/lib/config.php
index 62f4559..9acf7be 100644
--- a/lib/config.php
+++ b/lib/config.php
@@ -1,5 +1,6 @@
]+)><\/page>/i';
+ // Check if the pattern matches the input
+ if (preg_match($pattern, $input, $matches)) {
+ // Extract parameters
+ $parameters = [];
+ if (preg_match_all('/(\w+)="([^"]+)"/', $matches[1], $paramMatches, PREG_SET_ORDER)) {
+ foreach ($paramMatches as $paramMatch) {
+ $parameters[$paramMatch[1]] = $paramMatch[2];
+ }
+ }
+
+ // Remove the tag from the input
+ $output = preg_replace($pattern, '', $input, 1);
+
+ return ['parameters' => $parameters, 'output' => $output];
+ }
+
+ // If no match is found, return the original input
+ return ['parameters' => [], 'output' => $input];
}
-function getPage($page_name = null){
+function getPage($page_name = null): array|false|string
+{
global $routerConfig;
global $routerRequest;
@@ -42,6 +63,41 @@ function getPage($page_name = null){
else{
$page = file_get_contents($routerConfig["template_dir"] . "404.html");
}
+
+ $pageMetadata = parsePageTag($page);
+
+ $page = $pageMetadata["output"];
+
+ if(!empty($pageMetadata["parameters"]["minimal_permission_level"])){
+ $page_required_permission = intval($pageMetadata["parameters"]["minimal_permission_level"]);
+ }
+ else{
+ $page_required_permission = $routerConfig["default_page_permission_level"];
+ }
+
+ if(!empty($pageMetadata["parameters"]["secret"])){
+ $is_secret_page = intval($pageMetadata["parameters"]["secret"]);
+ }
+ else{
+ $is_secret_page = $routerConfig["default_page_secret"];
+ }
+
+ if($page_required_permission < $_SESSION["privilegelevel"]){
+ if($is_secret_page == 1) {
+ $page = file_get_contents($routerConfig["template_dir"] . "404.html"); //fake 404 error
+ }
+ else{
+ $page = file_get_contents($routerConfig["template_dir"] . "403.html"); //deny access if doesnt have permissions
+ }
+ }
+
+ if(!empty($pageMetadata["parameters"]["page_title"])){
+ $page_title = $pageMetadata["parameters"]["page_title"];
+ }
+ else{
+ $page_title = $page_name;
+ }
+
$navpages = generateNavigation();
$nav = str_replace("__NAV_PAGES__", $navpages, $nav);
@@ -49,5 +105,5 @@ function getPage($page_name = null){
$out = $skeleton;
$out = str_replace("__TEMPLATE__NAV__", $nav, $out);
$out = str_replace("__TEMPLATE__PAGE__", $page, $out);
- return str_replace("__TEMPLATE_PAGE_NAME__", $page_name, $out);
+ return str_replace("__TEMPLATE_PAGE_TITLE__", $page_title, $out);
}
\ No newline at end of file
diff --git a/lib/router.php b/lib/router.php
index e131ea9..ef49219 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -1,7 +1,8 @@
\ No newline at end of file
diff --git a/pages/memes/domov.html b/pages/memes/domov.html
index 24e5675..0115dbd 100644
--- a/pages/memes/domov.html
+++ b/pages/memes/domov.html
@@ -1,3 +1,4 @@
+