diff --git a/auth.js b/auth.js index 2ed33f1..8ef252e 100644 --- a/auth.js +++ b/auth.js @@ -41,8 +41,8 @@ function initAuth() { const headerButtons = document.querySelector(".header-buttons"); if (headerButtons) { // Insert after the third child if available. - if (headerButtons.children.length >= 4) { - headerButtons.insertBefore(restoreBtn, headerButtons.children[4]); + if (headerButtons.children.length >= 5) { + headerButtons.insertBefore(restoreBtn, headerButtons.children[5]); } else { headerButtons.appendChild(restoreBtn); } @@ -193,6 +193,63 @@ function initAuth() { document.getElementById("cancelRemoveUserBtn").addEventListener("click", function () { closeRemoveUserModal(); }); + + document.getElementById("changePasswordBtn").addEventListener("click", function() { + // Show the modal. + document.getElementById("changePasswordModal").style.display = "block"; + }); + + document.getElementById("closeChangePasswordModal").addEventListener("click", function() { + // Hide the modal. + document.getElementById("changePasswordModal").style.display = "none"; + }); + + document.getElementById("saveNewPasswordBtn").addEventListener("click", function() { + const oldPassword = document.getElementById("oldPassword").value.trim(); + const newPassword = document.getElementById("newPassword").value.trim(); + const confirmPassword = document.getElementById("confirmPassword").value.trim(); + + if (!oldPassword || !newPassword || !confirmPassword) { + showToast("Please fill in all fields."); + return; + } + + if (newPassword !== confirmPassword) { + showToast("New passwords do not match."); + return; + } + + // Prepare the data to send. + const data = { oldPassword, newPassword, confirmPassword }; + + // Send request to changePassword.php. + fetch("changePassword.php", { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json", + "X-CSRF-Token": window.csrfToken + }, + body: JSON.stringify(data) + }) + .then(response => response.json()) + .then(result => { + if (result.success) { + showToast(result.success); + // Optionally clear form fields and close modal. + document.getElementById("oldPassword").value = ""; + document.getElementById("newPassword").value = ""; + document.getElementById("confirmPassword").value = ""; + document.getElementById("changePasswordModal").style.display = "none"; + } else { + showToast("Error: " + (result.error || "Could not change password.")); + } + }) + .catch(error => { + console.error("Error changing password:", error); + showToast("Error changing password."); + }); + }); } function checkAuthentication(showLoginToast = true) { diff --git a/changePassword.php b/changePassword.php new file mode 100644 index 0000000..f894f4c --- /dev/null +++ b/changePassword.php @@ -0,0 +1,85 @@ + "Unauthorized"]); + exit; +} + +$username = $_SESSION['username'] ?? ''; +if (!$username) { + echo json_encode(["error" => "No username in session"]); + exit; +} + +// CSRF token check. +$headers = array_change_key_case(getallheaders(), CASE_LOWER); +$receivedToken = isset($headers['x-csrf-token']) ? trim($headers['x-csrf-token']) : ''; +if ($receivedToken !== $_SESSION['csrf_token']) { + echo json_encode(["error" => "Invalid CSRF token"]); + http_response_code(403); + exit; +} + +// Get POST data. +$data = json_decode(file_get_contents("php://input"), true); +$oldPassword = trim($data["oldPassword"] ?? ""); +$newPassword = trim($data["newPassword"] ?? ""); +$confirmPassword = trim($data["confirmPassword"] ?? ""); + +// Validate input. +if (!$oldPassword || !$newPassword || !$confirmPassword) { + echo json_encode(["error" => "All fields are required."]); + exit; +} +if ($newPassword !== $confirmPassword) { + echo json_encode(["error" => "New passwords do not match."]); + exit; +} + +// Path to users file. +$usersFile = USERS_DIR . USERS_FILE; +if (!file_exists($usersFile)) { + echo json_encode(["error" => "Users file not found"]); + exit; +} + +// Read current users. +$lines = file($usersFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); +$userFound = false; +$newLines = []; + +foreach ($lines as $line) { + list($storedUser, $storedHash, $storedRole) = explode(':', trim($line)); + if ($storedUser === $username) { + $userFound = true; + // Verify the old password. + if (!password_verify($oldPassword, $storedHash)) { + echo json_encode(["error" => "Old password is incorrect."]); + exit; + } + // Hash the new password. + $newHashedPassword = password_hash($newPassword, PASSWORD_BCRYPT); + // Rebuild the line with the new hash. + $newLines[] = $username . ":" . $newHashedPassword . ":" . $storedRole; + } else { + $newLines[] = $line; + } +} + +if (!$userFound) { + echo json_encode(["error" => "User not found."]); + exit; +} + +// Save updated users file. +if (file_put_contents($usersFile, implode(PHP_EOL, $newLines) . PHP_EOL)) { + echo json_encode(["success" => "Password updated successfully."]); +} else { + echo json_encode(["error" => "Could not update password."]); +} +?> \ No newline at end of file diff --git a/index.html b/index.html index 113daee..66809a1 100644 --- a/index.html +++ b/index.html @@ -91,6 +91,9 @@ + + + +