From c50c1bd122f23885ac5262ba2a03c00ac84c51d2 Mon Sep 17 00:00:00 2001 From: marc-go Date: Sun, 4 Oct 2026 19:21:38 +0200 Subject: [PATCH] Implement user authentication and registration; enhance error handling and database interaction in API --- .env | 1 + api/api.php | 75 ++++++++++++++++++++++++++----- api/auth/login.php | 50 +++++++++++++++++++++ api/setup/save.php | 37 ++++++++++++++- public/templates/setup/setup.html | 3 +- public/test.php | 13 ++++-- 6 files changed, 163 insertions(+), 16 deletions(-) create mode 100644 .env create mode 100644 api/auth/login.php diff --git a/.env b/.env new file mode 100644 index 0000000..dfaec6d --- /dev/null +++ b/.env @@ -0,0 +1 @@ +TOKEN_SIGNATURE=281361f952279bd9530734c67ed04aed2756f0fe00cb998cd6c28324f491484c \ No newline at end of file diff --git a/api/api.php b/api/api.php index 9f01168..130c365 100755 --- a/api/api.php +++ b/api/api.php @@ -1,13 +1,19 @@ authRequited) { - $this->checkAuth(); + if ($authRequired) { + if (!$this->checkAuth()) { + $status = 401; + $data = [ + "error" => "unauthorized", + "error_text" => "Authentication failed." + ]; + + $this->answer($status, $data); + } } } @@ -15,26 +21,73 @@ class gbAPI { return parse_ini_file(APP_PATH . ".env"); } - function generateToken() { + function generateToken($username) { $config = $this->getConfig(); // Generate Token - $token = bin2hex(random_bytes(32)); - $secret = $config["COOKIE_SIGNATURE"]; + $payload = [ + "user" => $username, + "auth" => true + ]; + $string = json_encode($payload); + $secret = $config["TOKEN_SIGNATURE"]; - return hash_hmac('sha256', $token, SECRET, true); + return hash_hmac("sha256", $string, $secret); } function checkAuth() { - if (isset($_SERVER)) + if (!isset($_SERVER["HTTP_X_API_KEY"]) && !isset($_COOKIE["auth_token"])) { + return false; + }elseif (isset($_COOKIE["auth_token"]) && isset($_COOKIE["username"])) { + // Check Token + $username = $_COOKIE["username"]; + $expected = $this->generateToken($username); + $given = $_COOKIE["auth_token"]; + + $result = hash_equals($expected, $give); + if ($result) { + return true; + } + }elseif (isset($_SERVER["HTTP_X_API_KEY"])) { + // Decode Token + $payload = json_decode(base64_decode($_SERVER["HTTP_X_API_KEY"]), true); + $username = $payload["username"]; + + $given = $payload["auth_token"]; + $expected = $this->generateToken($username); + + $result = hash_equals($expected, $given); + if ($result) { + return true; + } + } + + return false; } function answer($status, $data) { http_response_code($status); + Header ("Content-Type: application/json; charset=UTF-8"); $data = json_encode($data); - $json = '{"status":' . $status . ',"data":' $data . '}'; + $json = '{"status":' . $status . ',"data":' . $data . '}'; die($json); } + + function dbCommand($command, $expectResult, $stmtArgsRequired = false, $stmtArgs = []) { + $db_path = APP_PATH . "database.db"; + + $db = new PDO("sqlite:" . $db_path); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $stmt = $db->prepare($command); + $stmt->execute($stmtArgs); + + if ($expectResult) { + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + return $result; + } + } } \ No newline at end of file diff --git a/api/auth/login.php b/api/auth/login.php new file mode 100644 index 0000000..44d674b --- /dev/null +++ b/api/auth/login.php @@ -0,0 +1,50 @@ +answer(400, [ + "error" => "false_request_method", + "error_text" => "Only POST allowed" + ]); +} + +if (!isset($_POST["username"]) || !isset($_POST["password"])) { + $api->answer(400, [ + "error" => "missing_fields", + "error_text" => "Some fields are missing" + ]); +} + +$username = $_POST["username"]; +$password = $_POST["password"]; + +// Prepare SQL Command +$hash = hash("sha256", $password); + +$command = "SELECT username, password FROM users WHERE username = :username AND password = :password"; +$args = [ + ":username" => $username, + ":password" => $password +]; + +// Execute SQL Command +$result = $api->dbCommand($command, true, true, $args); + +// Check Result +if ($result) { + // Login successful. Generate Auth Token + $token = $api->generateToken($username); + + // Set cookies + setcookie("auth_token", $token, time() + 86400, "/"); + setcookie("username", $username, time() + 86400, "/"); +}else{ + $api->answer(401, [ + "error" => "unauthorized", + "error_text" => "A user with this password does not exists." + ]); +} \ No newline at end of file diff --git a/api/setup/save.php b/api/setup/save.php index 69e519b..d7fb894 100755 --- a/api/setup/save.php +++ b/api/setup/save.php @@ -2,4 +2,39 @@ // Load Main Libary require "../api.php"; -bin2hex(random_bytes(32)) \ No newline at end of file +$api = new gbAPI(true); + +// Check Request body +if ($_SERVER["REQUEST_METHOD"] !== "POST") { + $api->answer(400, [ + "error" => "false_request_method", + "error_text" => "Only POST allowed" + ]); +} + +if (!isset($_POST["username"]) || !isset($_POST["password"]) || !isset($_POST["password_repeat"])) { + $api->answer(400, [ + "error" => "missing_fields", + "error_text" => "Some fields are missing" + ]); +} + +$username = $_POST["username"]; +$password = $_POST["password"]; +$password_repeat = $_POST["password_repeat"]; + +// Check Passwords +if ($password !== $password_repeat) { + $api->answer(400, [ + "error" => "passwords_dont_match", + "error_text" => "The passwords does not match." + ]); +} + +// Hash Password +$hash = hash("sha256", $password); + + + +// CREATE DATABASE STRUCTURE +file_get_contents(APP_PATH . "db_structure.sql"); diff --git a/public/templates/setup/setup.html b/public/templates/setup/setup.html index e64f264..61983b9 100755 --- a/public/templates/setup/setup.html +++ b/public/templates/setup/setup.html @@ -100,7 +100,8 @@ method: "POST", body: JSON.stringify({ username: username, - password: password + password: password, + password_repeat: password_repeat }), headers: { "Content-type": "application/json; charset=UTF-8" diff --git a/public/test.php b/public/test.php index dc1114f..ade805b 100755 --- a/public/test.php +++ b/public/test.php @@ -1,7 +1,14 @@ $value) { +/*foreach($_SERVER as $key => $value) { echo $key . " === " . $value . "
"; -} +}*/ -//echo $_SERVER["HTTP_X_API_KEY"]; \ No newline at end of file +//echo $_SERVER["HTTP_X_API_KEY"]; + +$string = '{"user":"marc", "auth":true}'; +$secret = "281361f952279bd9530734c67ed04aed2756f0fe00cb998cd6c28324f491484c"; + +echo "Hash: " . hash_hmac("sha256", $string, $secret); + +echo "Decode: " . hash_equals($string, $secret); \ No newline at end of file