diff --git a/README.md b/README.md index 1719024..4f22400 100644 --- a/README.md +++ b/README.md @@ -137,10 +137,28 @@ FileRise is a lightweight, secure, self-hosted web application for uploading, sy - **Seamless Interaction:** - Both drop zones support smooth drag and drop interactions with animations and pointer event adjustments to prevent interference, ensuring that cards can be dropped reliably regardless of screen position. +### 🔒 Admin Panel & OpenID Connect (OIDC) Integration + +- **Flexible Authentication:** + - Supports multiple authentication methods including Form-based Login, Basic Auth, and OpenID Connect (OIDC). Allow disable of only two login options. + +- **Secure OIDC Authentication:** + - Integrates seamlessly with OIDC providers (e.g., Keycloak, Okta). + - Admin-configurable OIDC settings, including Provider URL, Client ID, Client Secret, and Redirect URI. + - All sensitive configurations are securely stored in an encrypted JSON file. + +- **Dynamic Admin Panel:** + - Intuitive Admin Panel with Material Icons for quick recognition and access. + - Allows administrators to easily manage authentication settings, user management, and login methods. + - Real-time validation prevents disabling all authentication methods simultaneously, ensuring continuous secure access. + --- ## Screenshots +**Light mode:** + + **Light mode:**  diff --git a/auth.js b/auth.js index cf015b6..d05a730 100644 --- a/auth.js +++ b/auth.js @@ -3,9 +3,14 @@ import { toggleVisibility, showToast, attachEnterKeyListener, showCustomConfirmM import { loadFileList, renderFileTable, displayFilePreview, initFileActions } from './fileManager.js'; import { loadFolderTree } from './folderManager.js'; -/** - * Updates the select element to reflect the stored items-per-page value. - */ +// Default OIDC configuration (can be overridden via API in production) +const currentOIDCConfig = { + providerUrl: "https://your-oidc-provider.com", + clientId: "YOUR_CLIENT_ID", + clientSecret: "YOUR_CLIENT_SECRET", + redirectUri: "https://yourdomain.com/auth.php?oidc=callback" +}; + function updateItemsPerPageSelect() { const selectElem = document.querySelector(".form-control.bottom-select"); if (selectElem) { @@ -14,11 +19,45 @@ function updateItemsPerPageSelect() { } } -/** - * Updates the UI for an authenticated user. - * This includes showing the main UI panels, attaching key listeners, updating header buttons, - * and displaying admin-only buttons if applicable. - */ +function updateLoginOptionsUI({ disableFormLogin, disableBasicAuth, disableOIDCLogin }) { + const authForm = document.getElementById("authForm"); + if (authForm) { + authForm.style.display = disableFormLogin ? "none" : "block"; + } + const basicAuthLink = document.querySelector("a[href='login_basic.php']"); + if (basicAuthLink) { + basicAuthLink.style.display = disableBasicAuth ? "none" : "inline-block"; + } + const oidcLoginBtn = document.getElementById("oidcLoginBtn"); + if (oidcLoginBtn) { + oidcLoginBtn.style.display = disableOIDCLogin ? "none" : "inline-block"; + } +} + +function updateLoginOptionsUIFromStorage() { + const disableFormLogin = localStorage.getItem("disableFormLogin") === "true"; + const disableBasicAuth = localStorage.getItem("disableBasicAuth") === "true"; + const disableOIDCLogin = localStorage.getItem("disableOIDCLogin") === "true"; + updateLoginOptionsUI({ disableFormLogin, disableBasicAuth, disableOIDCLogin }); +} + +function loadAdminConfigFunc() { + return fetch("getConfig.php", { credentials: "include" }) + .then(response => response.json()) + .then(config => { + localStorage.setItem("disableFormLogin", config.loginOptions.disableFormLogin); + localStorage.setItem("disableBasicAuth", config.loginOptions.disableBasicAuth); + localStorage.setItem("disableOIDCLogin", config.loginOptions.disableOIDCLogin); + updateLoginOptionsUIFromStorage(); + }) + .catch(() => { + localStorage.setItem("disableFormLogin", "false"); + localStorage.setItem("disableBasicAuth", "false"); + localStorage.setItem("disableOIDCLogin", "false"); + updateLoginOptionsUIFromStorage(); + }); +} + function updateAuthenticatedUI(data) { toggleVisibility("loginForm", false); toggleVisibility("mainOperations", true); @@ -29,45 +68,54 @@ function updateAuthenticatedUI(data) { attachEnterKeyListener("changePasswordModal", "saveNewPasswordBtn"); document.querySelector(".header-buttons").style.visibility = "visible"; - // If admin, show admin-only buttons; otherwise hide them. if (data.isAdmin) { - const addUserBtn = document.getElementById("addUserBtn"); - const removeUserBtn = document.getElementById("removeUserBtn"); - if (addUserBtn) addUserBtn.style.display = "block"; - if (removeUserBtn) removeUserBtn.style.display = "block"; let restoreBtn = document.getElementById("restoreFilesBtn"); if (!restoreBtn) { restoreBtn = document.createElement("button"); restoreBtn.id = "restoreFilesBtn"; restoreBtn.classList.add("btn", "btn-warning"); - // Using a material icon for restore. restoreBtn.innerHTML = 'restore_from_trash'; const headerButtons = document.querySelector(".header-buttons"); if (headerButtons) { - if (headerButtons.children.length >= 5) { - headerButtons.insertBefore(restoreBtn, headerButtons.children[5]); + if (headerButtons.children.length >= 3) { + headerButtons.insertBefore(restoreBtn, headerButtons.children[3]); } else { headerButtons.appendChild(restoreBtn); } } } restoreBtn.style.display = "block"; + + let adminPanelBtn = document.getElementById("adminPanelBtn"); + if (!adminPanelBtn) { + adminPanelBtn = document.createElement("button"); + adminPanelBtn.id = "adminPanelBtn"; + adminPanelBtn.classList.add("btn", "btn-info"); + // Use material icon for the admin panel button. + adminPanelBtn.innerHTML = 'admin_panel_settings'; + const headerButtons = document.querySelector(".header-buttons"); + if (headerButtons) { + // Insert the adminPanelBtn immediately after the restoreBtn. + if (restoreBtn.nextSibling) { + headerButtons.insertBefore(adminPanelBtn, restoreBtn.nextSibling); + } else { + headerButtons.appendChild(adminPanelBtn); + } + } + adminPanelBtn.addEventListener("click", openAdminPanel); + } else { + adminPanelBtn.style.display = "block"; + } } else { - const addUserBtn = document.getElementById("addUserBtn"); - const removeUserBtn = document.getElementById("removeUserBtn"); - if (addUserBtn) addUserBtn.style.display = "none"; - if (removeUserBtn) removeUserBtn.style.display = "none"; const restoreBtn = document.getElementById("restoreFilesBtn"); if (restoreBtn) restoreBtn.style.display = "none"; + const adminPanelBtn = document.getElementById("adminPanelBtn"); + if (adminPanelBtn) adminPanelBtn.style.display = "none"; } updateItemsPerPageSelect(); + updateLoginOptionsUIFromStorage(); } -/** - * Checks the user's authentication state and updates the UI accordingly. - * If in setup mode or not authenticated, it shows the proper UI elements. - * When authenticated, it calls updateAuthenticatedUI to handle the UI updates. - */ function checkAuthentication(showLoginToast = true) { return sendRequest("checkAuth.php") .then(data => { @@ -78,7 +126,7 @@ function checkAuthentication(showLoginToast = true) { toggleVisibility("mainOperations", false); document.querySelector(".header-buttons").style.visibility = "hidden"; toggleVisibility("addUserModal", true); - document.getElementById('newUsername').focus(); + document.getElementById("newUsername").focus(); return false; } window.setupMode = false; @@ -95,22 +143,13 @@ function checkAuthentication(showLoginToast = true) { return false; } }) - .catch(error => { - console.error("Error checking authentication:", error); - return false; - }); + .catch(() => false); } -/** - * Initializes authentication by checking the user's state and setting up event listeners. - * The UI will update automatically based on the auth state. - */ function initAuth() { - checkAuthentication(false).catch(error => { - console.error("Error checking authentication:", error); - }); + checkAuthentication(false); + loadAdminConfigFunc(); - // Attach login event listener. const authForm = document.getElementById("authForm"); if (authForm) { authForm.addEventListener("submit", function (event) { @@ -126,7 +165,6 @@ function initAuth() { sendRequest("auth.php", "POST", formData, { "X-CSRF-Token": window.csrfToken }) .then(data => { if (data.success) { - console.log("✅ Login successful. Reloading page."); sessionStorage.setItem("welcomeMessage", "Welcome back, " + formData.username + "!"); window.location.reload(); } else { @@ -145,11 +183,10 @@ function initAuth() { } } }) - .catch(error => console.error("❌ Error logging in:", error)); + .catch(() => {}); }); } - // Attach logout event listener. document.getElementById("logoutBtn").addEventListener("click", function () { fetch("logout.php", { method: "POST", @@ -157,14 +194,20 @@ function initAuth() { headers: { "X-CSRF-Token": window.csrfToken } }) .then(() => window.location.reload(true)) - .catch(error => console.error("Logout error:", error)); + .catch(() => {}); }); - // Add User functionality. + const oidcLoginBtn = document.getElementById("oidcLoginBtn"); + if (oidcLoginBtn) { + oidcLoginBtn.addEventListener("click", function () { + window.location.href = "auth.php?oidc"; + }); + } + document.getElementById("addUserBtn").addEventListener("click", function () { resetUserForm(); toggleVisibility("addUserModal", true); - document.getElementById('newUsername').focus(); + document.getElementById("newUsername").focus(); }); document.getElementById("saveUserBtn").addEventListener("click", function () { const newUsername = document.getElementById("newUsername").value.trim(); @@ -192,24 +235,19 @@ function initAuth() { if (data.success) { showToast("User added successfully!"); closeAddUserModal(); - // Re-check auth state to update the UI after adding a user. checkAuthentication(false); } else { showToast("Error: " + (data.error || "Could not add user")); } }) - .catch(error => console.error("Error adding user:", error)); - }); - document.getElementById("cancelUserBtn").addEventListener("click", function () { - closeAddUserModal(); + .catch(() => {}); }); + document.getElementById("cancelUserBtn").addEventListener("click", closeAddUserModal); - // Remove User functionality. document.getElementById("removeUserBtn").addEventListener("click", function () { loadUserList(); toggleVisibility("removeUserModal", true); }); - document.getElementById("deleteUserBtn").addEventListener("click", async function () { const selectElem = document.getElementById("removeUsernameSelect"); const usernameToRemove = selectElem.value; @@ -218,9 +256,7 @@ function initAuth() { return; } const confirmed = await showCustomConfirmModal("Are you sure you want to delete user " + usernameToRemove + "?"); - if (!confirmed) { - return; - } + if (!confirmed) return; fetch("removeUser.php", { method: "POST", credentials: "include", @@ -240,22 +276,17 @@ function initAuth() { showToast("Error: " + (data.error || "Could not remove user")); } }) - .catch(error => console.error("Error removing user:", error)); - }); - - document.getElementById("cancelRemoveUserBtn").addEventListener("click", function () { - closeRemoveUserModal(); + .catch(() => {}); }); + document.getElementById("cancelRemoveUserBtn").addEventListener("click", closeRemoveUserModal); document.getElementById("changePasswordBtn").addEventListener("click", function () { document.getElementById("changePasswordModal").style.display = "block"; document.getElementById("oldPassword").focus(); }); - document.getElementById("closeChangePasswordModal").addEventListener("click", function () { 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(); @@ -290,13 +321,240 @@ function initAuth() { showToast("Error: " + (result.error || "Could not change password.")); } }) - .catch(error => { - console.error("Error changing password:", error); + .catch(() => { showToast("Error changing password."); }); }); } +function loadOIDCConfig() { + return fetch("getConfig.php", { credentials: "include" }) + .then(response => response.json()) + .then(config => { + if (config.oidc) { + Object.assign(currentOIDCConfig, config.oidc); + } + return currentOIDCConfig; + }) + .catch(() => currentOIDCConfig); +} + +function openAdminPanel() { + fetch("getConfig.php", { credentials: "include" }) + .then(response => response.json()) + .then(config => { + if (config.oidc) { + Object.assign(currentOIDCConfig, config.oidc); + } + const isDarkMode = document.body.classList.contains("dark-mode"); + const overlayBackground = isDarkMode ? "rgba(0, 0, 0, 0.7)" : "rgba(0, 0, 0, 0.3)"; + const modalContentStyles = ` + background: ${isDarkMode ? "#2c2c2c" : "#fff"}; + color: ${isDarkMode ? "#e0e0e0" : "#000"}; + padding: 20px; + max-width: 600px; + width: 90%; + border-radius: 8px; + position: relative; + overflow-y: auto; + max-height: 90vh; + border: ${isDarkMode ? "1px solid #444" : "1px solid #ccc"}; + `; + let adminModal = document.getElementById("adminPanelModal"); + if (!adminModal) { + adminModal = document.createElement("div"); + adminModal.id = "adminPanelModal"; + adminModal.style.cssText = ` + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: ${overlayBackground}; + display: flex; + justify-content: center; + align-items: center; + z-index: 3000; + `; + adminModal.innerHTML = ` +
+`; + document.body.appendChild(adminModal); + document.getElementById("closeAdminPanel").addEventListener("click", closeAdminPanel); + adminModal.addEventListener("click", function (e) { + if (e.target === adminModal) { + closeAdminPanel(); + } + }); + document.getElementById("cancelAdminSettings").addEventListener("click", closeAdminPanel); + document.getElementById("adminOpenAddUser").addEventListener("click", function () { + toggleVisibility("addUserModal", true); + document.getElementById("newUsername").focus(); + }); + document.getElementById("adminOpenRemoveUser").addEventListener("click", function () { + loadUserList(); + toggleVisibility("removeUserModal", true); + }); + document.getElementById("saveAdminSettings").addEventListener("click", function () { + const disableFormLoginCheckbox = document.getElementById("disableFormLogin"); + const disableBasicAuthCheckbox = document.getElementById("disableBasicAuth"); + const disableOIDCLoginCheckbox = document.getElementById("disableOIDCLogin"); + const totalDisabled = [disableFormLoginCheckbox, disableBasicAuthCheckbox, disableOIDCLoginCheckbox] + .filter(cb => cb.checked).length; + if (totalDisabled === 3) { + showToast("At least one login method must remain enabled."); + disableOIDCLoginCheckbox.checked = false; + localStorage.setItem("disableOIDCLogin", "false"); + updateLoginOptionsUI({ + disableFormLogin: disableFormLoginCheckbox.checked, + disableBasicAuth: disableBasicAuthCheckbox.checked, + disableOIDCLogin: disableOIDCLoginCheckbox.checked + }); + return; + } + const newOIDCConfig = { + providerUrl: document.getElementById("oidcProviderUrl").value.trim(), + clientId: document.getElementById("oidcClientId").value.trim(), + clientSecret: document.getElementById("oidcClientSecret").value.trim(), + redirectUri: document.getElementById("oidcRedirectUri").value.trim() + }; + const disableFormLogin = disableFormLoginCheckbox.checked; + const disableBasicAuth = disableBasicAuthCheckbox.checked; + const disableOIDCLogin = disableOIDCLoginCheckbox.checked; + sendRequest("updateConfig.php", "POST", { + oidc: newOIDCConfig, + disableFormLogin, + disableBasicAuth, + disableOIDCLogin + }, { "X-CSRF-Token": window.csrfToken }) + .then(response => { + if (response.success) { + showToast("Settings updated successfully."); + localStorage.setItem("disableFormLogin", disableFormLogin); + localStorage.setItem("disableBasicAuth", disableBasicAuth); + localStorage.setItem("disableOIDCLogin", disableOIDCLogin); + updateLoginOptionsUI({ disableFormLogin, disableBasicAuth, disableOIDCLogin }); + closeAdminPanel(); + } else { + showToast("Error updating settings: " + (response.error || "Unknown error")); + } + }) + .catch(() => {}); + }); + const disableFormLoginCheckbox = document.getElementById("disableFormLogin"); + const disableBasicAuthCheckbox = document.getElementById("disableBasicAuth"); + const disableOIDCLoginCheckbox = document.getElementById("disableOIDCLogin"); + function enforceLoginOptionConstraint(changedCheckbox) { + const totalDisabled = [disableFormLoginCheckbox, disableBasicAuthCheckbox, disableOIDCLoginCheckbox] + .filter(cb => cb.checked).length; + if (changedCheckbox.checked && totalDisabled === 3) { + showToast("At least one login method must remain enabled."); + changedCheckbox.checked = false; + } + } + disableFormLoginCheckbox.addEventListener("change", function () { + enforceLoginOptionConstraint(this); + }); + disableBasicAuthCheckbox.addEventListener("change", function () { + enforceLoginOptionConstraint(this); + }); + disableOIDCLoginCheckbox.addEventListener("change", function () { + enforceLoginOptionConstraint(this); + }); + document.getElementById("disableFormLogin").checked = localStorage.getItem("disableFormLogin") === "true"; + document.getElementById("disableBasicAuth").checked = localStorage.getItem("disableBasicAuth") === "true"; + document.getElementById("disableOIDCLogin").checked = localStorage.getItem("disableOIDCLogin") === "true"; + } else { + const isDarkMode = document.body.classList.contains("dark-mode"); + const overlayBackground = isDarkMode ? "rgba(0, 0, 0, 0.7)" : "rgba(0, 0, 0, 0.3)"; + adminModal.style.backgroundColor = overlayBackground; + const modalContent = adminModal.querySelector(".modal-content"); + if (modalContent) { + modalContent.style.background = isDarkMode ? "#2c2c2c" : "#fff"; + modalContent.style.color = isDarkMode ? "#e0e0e0" : "#000"; + modalContent.style.border = isDarkMode ? "1px solid #444" : "1px solid #ccc"; + } + document.getElementById("oidcProviderUrl").value = currentOIDCConfig.providerUrl; + document.getElementById("oidcClientId").value = currentOIDCConfig.clientId; + document.getElementById("oidcClientSecret").value = currentOIDCConfig.clientSecret; + document.getElementById("oidcRedirectUri").value = currentOIDCConfig.redirectUri; + document.getElementById("disableFormLogin").checked = localStorage.getItem("disableFormLogin") === "true"; + document.getElementById("disableBasicAuth").checked = localStorage.getItem("disableBasicAuth") === "true"; + document.getElementById("disableOIDCLogin").checked = localStorage.getItem("disableOIDCLogin") === "true"; + adminModal.style.display = "flex"; + } + }) + .catch(() => { + let adminModal = document.getElementById("adminPanelModal"); + if (adminModal) { + document.getElementById("oidcProviderUrl").value = currentOIDCConfig.providerUrl; + document.getElementById("oidcClientId").value = currentOIDCConfig.clientId; + document.getElementById("oidcClientSecret").value = currentOIDCConfig.clientSecret; + document.getElementById("oidcRedirectUri").value = currentOIDCConfig.redirectUri; + adminModal.style.display = "flex"; + } else { + openAdminPanel(); + } + }); +} + +function closeAdminPanel() { + const adminModal = document.getElementById("adminPanelModal"); + if (adminModal) { + adminModal.style.display = "none"; + } +} + window.changeItemsPerPage = function (value) { localStorage.setItem("itemsPerPage", value); const folder = window.currentFolder || "root"; @@ -307,6 +565,10 @@ window.changeItemsPerPage = function (value) { document.addEventListener("DOMContentLoaded", function () { updateItemsPerPageSelect(); + const disableFormLogin = localStorage.getItem("disableFormLogin") === "true"; + const disableBasicAuth = localStorage.getItem("disableBasicAuth") === "true"; + const disableOIDCLogin = localStorage.getItem("disableOIDCLogin") === "true"; + updateLoginOptionsUI({ disableFormLogin, disableBasicAuth, disableOIDCLogin }); }); function resetUserForm() { @@ -342,7 +604,7 @@ function loadUserList() { closeRemoveUserModal(); } }) - .catch(error => console.error("Error loading user list:", error)); + .catch(() => {}); } export { initAuth, checkAuthentication }; \ No newline at end of file diff --git a/auth.php b/auth.php index 185e813..834a22a 100644 --- a/auth.php +++ b/auth.php @@ -1,19 +1,83 @@ 'Failed to decrypt admin configuration.']); + exit; + } + $adminConfig = json_decode($decryptedContent, true); + if (isset($adminConfig['oidc'])) { + $oidcConfig = $adminConfig['oidc']; + $oidc_provider_url = !empty($oidcConfig['providerUrl']) ? $oidcConfig['providerUrl'] : 'https://your-oidc-provider.com'; + $oidc_client_id = !empty($oidcConfig['clientId']) ? $oidcConfig['clientId'] : 'YOUR_CLIENT_ID'; + $oidc_client_secret = !empty($oidcConfig['clientSecret']) ? $oidcConfig['clientSecret'] : 'YOUR_CLIENT_SECRET'; + $oidc_redirect_uri = !empty($oidcConfig['redirectUri']) ? $oidcConfig['redirectUri'] : 'https://yourdomain.com/auth.php?oidc=callback'; + } else { + $oidc_provider_url = 'https://your-oidc-provider.com'; + $oidc_client_id = 'YOUR_CLIENT_ID'; + $oidc_client_secret = 'YOUR_CLIENT_SECRET'; + $oidc_redirect_uri = 'https://yourdomain.com/auth.php?oidc=callback'; + } + } else { + $oidc_provider_url = 'https://your-oidc-provider.com'; + $oidc_client_id = 'YOUR_CLIENT_ID'; + $oidc_client_secret = 'YOUR_CLIENT_SECRET'; + $oidc_redirect_uri = 'https://yourdomain.com/auth.php?oidc=callback'; + } + + $oidc = new Jumbojett\OpenIDConnectClient( + $oidc_provider_url, + $oidc_client_id, + $oidc_client_secret + ); + $oidc->setRedirectURL($oidc_redirect_uri); + + // Since PKCE is disabled in Keycloak, we do not set any PKCE parameters. + + if ($_GET['oidc'] === 'callback') { + try { + $oidc->authenticate(); + $username = $oidc->requestUserInfo('preferred_username'); + session_regenerate_id(true); + $_SESSION["authenticated"] = true; + $_SESSION["username"] = $username; + $_SESSION["isAdmin"] = false; + header("Location: index.html"); + exit(); + } catch (Exception $e) { + echo json_encode(["error" => "Authentication failed: " . $e->getMessage()]); + exit(); + } + } else { + try { + $oidc->authenticate(); + exit(); + } catch (Exception $e) { + echo json_encode(["error" => "Authentication initiation failed: " . $e->getMessage()]); + exit(); + } + } +} + +// --- Fallback: Form-based Authentication --- + $usersFile = USERS_DIR . USERS_FILE; - -// --- Brute Force Protection Settings --- $maxAttempts = 5; -$lockoutTime = 30 * 60; // 30 minutes in seconds -$attemptsFile = USERS_DIR . 'failed_logins.json'; // JSON file for tracking failed login attempts -$failedLogFile = USERS_DIR . 'failed_login.log'; // Plain text log for fail2ban - -// Persistent tokens file for "Remember me" +$lockoutTime = 30 * 60; +$attemptsFile = USERS_DIR . 'failed_logins.json'; +$failedLogFile = USERS_DIR . 'failed_login.log'; $persistentTokensFile = USERS_DIR . 'persistent_tokens.json'; -// Load failed attempts data from file. function loadFailedAttempts($file) { if (file_exists($file)) { $data = json_decode(file_get_contents($file), true); @@ -24,30 +88,23 @@ function loadFailedAttempts($file) { return []; } -// Save failed attempts data to file. function saveFailedAttempts($file, $data) { file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT)); } -// Get current IP address. $ip = $_SERVER['REMOTE_ADDR']; $currentTime = time(); - -// Load failed attempts. $failedAttempts = loadFailedAttempts($attemptsFile); -// Check if this IP is currently locked out. if (isset($failedAttempts[$ip])) { $attemptData = $failedAttempts[$ip]; if ($attemptData['count'] >= $maxAttempts && ($currentTime - $attemptData['last_attempt']) < $lockoutTime) { echo json_encode(["error" => "Too many failed login attempts. Please try again later."]); - exit; + exit(); } } -// --- Authentication Function --- -function authenticate($username, $password) -{ +function authenticate($username, $password) { global $usersFile; if (!file_exists($usersFile)) { return false; @@ -56,51 +113,41 @@ function authenticate($username, $password) foreach ($lines as $line) { list($storedUser, $storedPass, $storedRole) = explode(':', trim($line), 3); if ($username === $storedUser && password_verify($password, $storedPass)) { - return $storedRole; // Return the user's role + return $storedRole; } } return false; } -// Get JSON input. $data = json_decode(file_get_contents("php://input"), true); $username = trim($data["username"] ?? ""); $password = trim($data["password"] ?? ""); $rememberMe = isset($data["remember_me"]) && $data["remember_me"] === true; -// Validate input: ensure both fields are provided. if (!$username || !$password) { echo json_encode(["error" => "Username and password are required"]); - exit; + exit(); } -// Validate username format. if (!preg_match('/^[A-Za-z0-9_\- ]+$/', $username)) { echo json_encode(["error" => "Invalid username format. Only letters, numbers, underscores, dashes, and spaces are allowed."]); - exit; + exit(); } -// Attempt to authenticate the user. $userRole = authenticate($username, $password); if ($userRole !== false) { - // On successful login, reset failed attempts for this IP. if (isset($failedAttempts[$ip])) { unset($failedAttempts[$ip]); saveFailedAttempts($attemptsFile, $failedAttempts); } - // Regenerate session ID to mitigate session fixation attacks. session_regenerate_id(true); $_SESSION["authenticated"] = true; $_SESSION["username"] = $username; - $_SESSION["isAdmin"] = ($userRole === "1"); // "1" indicates admin - - // If "Remember me" is checked, generate a persistent login token. + $_SESSION["isAdmin"] = ($userRole === "1"); + if ($rememberMe) { - // Generate a secure random token. $token = bin2hex(random_bytes(32)); - $expiry = time() + (30 * 24 * 60 * 60); // 30 days - - // Load existing persistent tokens. + $expiry = time() + (30 * 24 * 60 * 60); $persistentTokens = []; if (file_exists($persistentTokensFile)) { $encryptedContent = file_get_contents($persistentTokensFile); @@ -110,7 +157,6 @@ if ($userRole !== false) { $persistentTokens = []; } } - // Save token along with username, expiry, and admin status. $persistentTokens[$token] = [ "username" => $username, "expiry" => $expiry, @@ -118,13 +164,11 @@ if ($userRole !== false) { ]; $encryptedContent = encryptData(json_encode($persistentTokens, JSON_PRETTY_PRINT), $encryptionKey); file_put_contents($persistentTokensFile, $encryptedContent, LOCK_EX); - // Set the cookie. (Assuming $secure is defined in config.php.) setcookie('remember_me_token', $token, $expiry, '/', '', $secure, true); } echo json_encode(["success" => "Login successful", "isAdmin" => $_SESSION["isAdmin"]]); } else { - // On failed login, update failed attempts. if (isset($failedAttempts[$ip])) { $failedAttempts[$ip]['count']++; $failedAttempts[$ip]['last_attempt'] = $currentTime; @@ -132,11 +176,8 @@ if ($userRole !== false) { $failedAttempts[$ip] = ['count' => 1, 'last_attempt' => $currentTime]; } saveFailedAttempts($attemptsFile, $failedAttempts); - - // Log the failed attempt to the plain text log for fail2ban. $logLine = date('Y-m-d H:i:s') . " - Failed login attempt for username: " . $username . " from IP: " . $ip . PHP_EOL; file_put_contents($failedLogFile, $logLine, FILE_APPEND); - echo json_encode(["error" => "Invalid credentials"]); } ?> \ No newline at end of file diff --git a/config.php b/config.php index 060f8b4..caa59b7 100644 --- a/config.php +++ b/config.php @@ -1,7 +1,7 @@ 7200, 'path' => '/', - 'domain' => '', // Specify your domain if needed + 'domain' => '', // Set your domain as needed. 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax' ]; session_set_cookie_params($cookieParams); - ini_set('session.gc_maxlifetime', 7200); session_start(); -// Generate CSRF token if not already set. if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } -// Auto-login via persistent token if session is not active. +// Auto-login via persistent token. if (!isset($_SESSION["authenticated"]) && isset($_COOKIE['remember_me_token'])) { $persistentTokensFile = USERS_DIR . 'persistent_tokens.json'; $persistentTokens = []; @@ -91,15 +87,12 @@ if (!isset($_SESSION["authenticated"]) && isset($_COOKIE['remember_me_token'])) $persistentTokens = []; } } - if (is_array($persistentTokens) && isset($persistentTokens[$_COOKIE['remember_me_token']])) { + if (isset($persistentTokens[$_COOKIE['remember_me_token']])) { $tokenData = $persistentTokens[$_COOKIE['remember_me_token']]; if ($tokenData['expiry'] >= time()) { - // Token is valid; auto-authenticate the user. $_SESSION["authenticated"] = true; $_SESSION["username"] = $tokenData["username"]; - $_SESSION["isAdmin"] = $tokenData["isAdmin"]; // Restore admin status from the token } else { - // Token expired; remove it and clear the cookie. unset($persistentTokens[$_COOKIE['remember_me_token']]); $newEncryptedContent = encryptData(json_encode($persistentTokens, JSON_PRETTY_PRINT), $encryptionKey); file_put_contents($persistentTokensFile, $newEncryptedContent, LOCK_EX); @@ -108,11 +101,8 @@ if (!isset($_SESSION["authenticated"]) && isset($_COOKIE['remember_me_token'])) } } -// Define BASE_URL (this should point to where index.html is, e.g. your uploads directory) define('BASE_URL', 'http://yourwebsite/uploads/'); -// If BASE_URL is still the default placeholder, use the server's HTTP_HOST. -// Otherwise, use BASE_URL and append share.php. if (strpos(BASE_URL, 'yourwebsite') !== false) { $defaultShareUrl = isset($_SERVER['HTTP_HOST']) ? "http://" . $_SERVER['HTTP_HOST'] . "/share.php" @@ -120,6 +110,5 @@ if (strpos(BASE_URL, 'yourwebsite') !== false) { } else { $defaultShareUrl = rtrim(BASE_URL, '/') . "/share.php"; } - define('SHARE_URL', getenv('SHARE_URL') ? getenv('SHARE_URL') : $defaultShareUrl); ?> \ No newline at end of file diff --git a/dragAndDrop.js b/dragAndDrop.js index 2d5c11d..d100819 100644 --- a/dragAndDrop.js +++ b/dragAndDrop.js @@ -6,23 +6,23 @@ export function loadSidebarOrder() { if (!sidebar) return; const orderStr = localStorage.getItem('sidebarOrder'); if (orderStr) { - const order = JSON.parse(orderStr); - if (order.length > 0) { - // Ensure main wrapper is visible. - const mainWrapper = document.querySelector('.main-wrapper'); - if (mainWrapper) { - mainWrapper.style.display = 'flex'; + const order = JSON.parse(orderStr); + if (order.length > 0) { + // Ensure main wrapper is visible. + const mainWrapper = document.querySelector('.main-wrapper'); + if (mainWrapper) { + mainWrapper.style.display = 'flex'; + } + // For each saved ID, move the card into the sidebar. + order.forEach(id => { + const card = document.getElementById(id); + if (card && card.parentNode.id !== 'sidebarDropArea') { + sidebar.appendChild(card); + // Animate vertical slide for sidebar card + animateVerticalSlide(card); + } + }); } - // For each saved ID, move the card into the sidebar. - order.forEach(id => { - const card = document.getElementById(id); - if (card && card.parentNode.id !== 'sidebarDropArea') { - sidebar.appendChild(card); - // Animate vertical slide for sidebar card - animateVerticalSlide(card); - } - }); - } } updateSidebarVisibility(); } @@ -31,16 +31,16 @@ export function loadSidebarOrder() { function updateSidebarVisibility() { const sidebar = document.getElementById('sidebarDropArea'); if (sidebar) { - const cards = sidebar.querySelectorAll('#uploadCard, #folderManagementCard'); - if (cards.length > 0) { - sidebar.classList.add('active'); - sidebar.style.display = 'block'; - } else { - sidebar.classList.remove('active'); - sidebar.style.display = 'none'; - } - // Save the current order in localStorage. - saveSidebarOrder(); + const cards = sidebar.querySelectorAll('#uploadCard, #folderManagementCard'); + if (cards.length > 0) { + sidebar.classList.add('active'); + sidebar.style.display = 'block'; + } else { + sidebar.classList.remove('active'); + sidebar.style.display = 'none'; + } + // Save the current order in localStorage. + saveSidebarOrder(); } } @@ -48,21 +48,21 @@ function updateSidebarVisibility() { function updateTopZoneLayout() { const leftCol = document.getElementById('leftCol'); const rightCol = document.getElementById('rightCol'); - + const leftIsEmpty = !leftCol.querySelector('#uploadCard'); const rightIsEmpty = !rightCol.querySelector('#folderManagementCard'); if (leftIsEmpty && !rightIsEmpty) { - leftCol.style.display = 'none'; - rightCol.style.margin = '0 auto'; + leftCol.style.display = 'none'; + rightCol.style.margin = '0 auto'; } else if (rightIsEmpty && !leftIsEmpty) { - rightCol.style.display = 'none'; - leftCol.style.margin = '0 auto'; + rightCol.style.display = 'none'; + leftCol.style.margin = '0 auto'; } else { - leftCol.style.display = ''; - rightCol.style.display = ''; - leftCol.style.margin = ''; - rightCol.style.margin = ''; + leftCol.style.display = ''; + rightCol.style.display = ''; + leftCol.style.margin = ''; + rightCol.style.margin = ''; } } @@ -70,10 +70,10 @@ function updateTopZoneLayout() { function addTopZoneHighlight() { const topZone = document.getElementById('uploadFolderRow'); if (topZone) { - topZone.classList.add('highlight'); - if (topZone.querySelectorAll('#uploadCard, #folderManagementCard').length === 0) { - topZone.style.minHeight = '375px'; - } + topZone.classList.add('highlight'); + if (topZone.querySelectorAll('#uploadCard, #folderManagementCard').length === 0) { + topZone.style.minHeight = '375px'; + } } } @@ -81,8 +81,8 @@ function addTopZoneHighlight() { function removeTopZoneHighlight() { const topZone = document.getElementById('uploadFolderRow'); if (topZone) { - topZone.classList.remove('highlight'); - topZone.style.minHeight = ''; + topZone.classList.remove('highlight'); + topZone.style.minHeight = ''; } } @@ -93,14 +93,14 @@ function animateVerticalSlide(card) { // Force reflow. card.offsetWidth; requestAnimationFrame(() => { - card.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; - card.style.transform = 'translateY(0)'; - card.style.opacity = '1'; + card.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; + card.style.transform = 'translateY(0)'; + card.style.opacity = '1'; }); setTimeout(() => { - card.style.transition = ''; - card.style.transform = ''; - card.style.opacity = ''; + card.style.transition = ''; + card.style.transform = ''; + card.style.opacity = ''; }, 310); } @@ -111,16 +111,16 @@ function insertCardInSidebar(card, event) { const existingCards = Array.from(sidebar.querySelectorAll('#uploadCard, #folderManagementCard')); let inserted = false; for (const currentCard of existingCards) { - const rect = currentCard.getBoundingClientRect(); - const midY = rect.top + rect.height / 2; - if (event.clientY < midY) { - sidebar.insertBefore(card, currentCard); - inserted = true; - break; - } + const rect = currentCard.getBoundingClientRect(); + const midY = rect.top + rect.height / 2; + if (event.clientY < midY) { + sidebar.insertBefore(card, currentCard); + inserted = true; + break; + } } if (!inserted) { - sidebar.appendChild(card); + sidebar.appendChild(card); } // Ensure card fills the sidebar. card.style.width = '100%'; @@ -131,34 +131,34 @@ function insertCardInSidebar(card, event) { function saveSidebarOrder() { const sidebar = document.getElementById('sidebarDropArea'); if (sidebar) { - const cards = sidebar.querySelectorAll('#uploadCard, #folderManagementCard'); - const order = Array.from(cards).map(card => card.id); - localStorage.setItem('sidebarOrder', JSON.stringify(order)); + const cards = sidebar.querySelectorAll('#uploadCard, #folderManagementCard'); + const order = Array.from(cards).map(card => card.id); + localStorage.setItem('sidebarOrder', JSON.stringify(order)); } } // Helper: move cards from sidebar back to the top drop area when on small screens. function moveSidebarCardsToTop() { if (window.innerWidth < 1205) { - const sidebar = document.getElementById('sidebarDropArea'); - if (!sidebar) return; - const cards = Array.from(sidebar.querySelectorAll('#uploadCard, #folderManagementCard')); - cards.forEach(card => { - const orig = document.getElementById(card.dataset.originalContainerId); - if (orig) { - orig.appendChild(card); - animateVerticalSlide(card); - } - }); - updateSidebarVisibility(); - updateTopZoneLayout(); + const sidebar = document.getElementById('sidebarDropArea'); + if (!sidebar) return; + const cards = Array.from(sidebar.querySelectorAll('#uploadCard, #folderManagementCard')); + cards.forEach(card => { + const orig = document.getElementById(card.dataset.originalContainerId); + if (orig) { + orig.appendChild(card); + animateVerticalSlide(card); + } + }); + updateSidebarVisibility(); + updateTopZoneLayout(); } } // Listen for window resize to automatically move sidebar cards back to top on small screens. window.addEventListener('resize', function () { if (window.innerWidth < 1205) { - moveSidebarCardsToTop(); + moveSidebarCardsToTop(); } }); @@ -167,198 +167,198 @@ function ensureTopZonePlaceholder() { const topZone = document.getElementById('uploadFolderRow'); if (!topZone) return; if (topZone.querySelectorAll('#uploadCard, #folderManagementCard').length === 0) { - let placeholder = topZone.querySelector('.placeholder'); - if (!placeholder) { - placeholder = document.createElement('div'); - placeholder.className = 'placeholder'; - placeholder.style.visibility = 'hidden'; - placeholder.style.display = 'block'; - placeholder.style.width = '100%'; - placeholder.style.height = '375px'; - topZone.appendChild(placeholder); - } + let placeholder = topZone.querySelector('.placeholder'); + if (!placeholder) { + placeholder = document.createElement('div'); + placeholder.className = 'placeholder'; + placeholder.style.visibility = 'hidden'; + placeholder.style.display = 'block'; + placeholder.style.width = '100%'; + placeholder.style.height = '375px'; + topZone.appendChild(placeholder); + } } else { - const placeholder = topZone.querySelector('.placeholder'); - if (placeholder) placeholder.remove(); + const placeholder = topZone.querySelector('.placeholder'); + if (placeholder) placeholder.remove(); } } // This sets up all drag-and-drop event listeners for cards. export function initDragAndDrop() { function run() { - const draggableCards = document.querySelectorAll('#uploadCard, #folderManagementCard'); - draggableCards.forEach(card => { - if (!card.dataset.originalContainerId) { - card.dataset.originalContainerId = card.parentNode.id; - } - const header = card.querySelector('.card-header'); - if (header) { - header.classList.add('drag-header'); - } - - let isDragging = false; - let dragTimer = null; - let offsetX = 0, offsetY = 0; - let initialLeft, initialTop; - - if (header) { - header.addEventListener('mousedown', function (e) { - e.preventDefault(); - const card = this.closest('.card'); - const rect = card.getBoundingClientRect(); - const originX = ((e.clientX - rect.left) / rect.width) * 100; - const originY = ((e.clientY - rect.top) / rect.height) * 100; - card.style.transformOrigin = `${originX}% ${originY}%`; - dragTimer = setTimeout(() => { - isDragging = true; - card.classList.add('dragging'); - // Disable pointer events on the card so it doesn't block drop detection. - card.style.pointerEvents = 'none'; - addTopZoneHighlight(); - const sidebar = document.getElementById('sidebarDropArea'); - if (sidebar) { - sidebar.classList.add('active'); - sidebar.style.display = 'block'; - sidebar.classList.add('highlight'); - // Force the sidebar to have a tall drop zone while dragging. - sidebar.style.height = '800px'; - } - const rect = card.getBoundingClientRect(); - initialLeft = rect.left + window.pageXOffset; - initialTop = rect.top + window.pageYOffset; - offsetX = e.pageX - initialLeft; - offsetY = e.pageY - initialTop; - document.body.appendChild(card); - card.style.position = 'absolute'; - card.style.left = initialLeft + 'px'; - card.style.top = initialTop + 'px'; - card.style.width = rect.width + 'px'; - card.style.zIndex = '10000'; - }, 500); - }); - header.addEventListener('mouseup', function () { - clearTimeout(dragTimer); - }); - } - - document.addEventListener('mousemove', function (e) { - if (isDragging) { - card.style.left = (e.pageX - offsetX) + 'px'; - card.style.top = (e.pageY - offsetY) + 'px'; - } - }); - - document.addEventListener('mouseup', function (e) { - if (isDragging) { - isDragging = false; - // Re-enable pointer events on the card. - card.style.pointerEvents = ''; - card.classList.remove('dragging'); - removeTopZoneHighlight(); - const sidebar = document.getElementById('sidebarDropArea'); - if (sidebar) { - sidebar.classList.remove('highlight'); - // Remove the forced height once the drag ends. - sidebar.style.height = ''; + const draggableCards = document.querySelectorAll('#uploadCard, #folderManagementCard'); + draggableCards.forEach(card => { + if (!card.dataset.originalContainerId) { + card.dataset.originalContainerId = card.parentNode.id; } - - const leftCol = document.getElementById('leftCol'); - const rightCol = document.getElementById('rightCol'); - let droppedInSidebar = false; - let droppedInTop = false; - - const sidebarElem = document.getElementById('sidebarDropArea'); - if (sidebarElem) { - // Instead of using elementsFromPoint, use a virtual drop zone. - const rect = sidebarElem.getBoundingClientRect(); - // Define a drop zone from the top of the sidebar to 1000px below its top. - const dropZoneBottom = rect.top + 800; - if ( - e.clientX >= rect.left && - e.clientX <= rect.right && - e.clientY >= rect.top && - e.clientY <= dropZoneBottom - ) { - insertCardInSidebar(card, e); - droppedInSidebar = true; - sidebarElem.blur(); - } + const header = card.querySelector('.card-header'); + if (header) { + header.classList.add('drag-header'); } - - const topRow = document.getElementById('uploadFolderRow'); - if (!droppedInSidebar && topRow) { - const rect = topRow.getBoundingClientRect(); - if ( - e.clientX >= rect.left && - e.clientX <= rect.right && - e.clientY >= rect.top && - e.clientY <= rect.bottom - ) { - let container; - if (card.id === 'uploadCard') { - container = document.getElementById('leftCol'); - } else if (card.id === 'folderManagementCard') { - container = document.getElementById('rightCol'); + + let isDragging = false; + let dragTimer = null; + let offsetX = 0, offsetY = 0; + let initialLeft, initialTop; + + if (header) { + header.addEventListener('mousedown', function (e) { + e.preventDefault(); + const card = this.closest('.card'); + // Capture the card's initial bounding rectangle once. + const initialRect = card.getBoundingClientRect(); + const originX = ((e.clientX - initialRect.left) / initialRect.width) * 100; + const originY = ((e.clientY - initialRect.top) / initialRect.height) * 100; + card.style.transformOrigin = `${originX}% ${originY}%`; + + // Store the initial rect so we use it later. + dragTimer = setTimeout(() => { + isDragging = true; + card.classList.add('dragging'); + card.style.pointerEvents = 'none'; + addTopZoneHighlight(); + + const sidebar = document.getElementById('sidebarDropArea'); + if (sidebar) { + sidebar.classList.add('active'); + sidebar.style.display = 'block'; + sidebar.classList.add('highlight'); + sidebar.style.height = '800px'; + } + + // Use the stored initialRect rather than recalculating. + initialLeft = initialRect.left + window.pageXOffset; + initialTop = initialRect.top + window.pageYOffset; + offsetX = e.pageX - initialLeft; + offsetY = e.pageY - initialTop; + + // Append card to body and fix its dimensions to prevent shrinking. + document.body.appendChild(card); + card.style.position = 'absolute'; + card.style.left = initialLeft + 'px'; + card.style.top = initialTop + 'px'; + card.style.width = initialRect.width + 'px'; + card.style.height = initialRect.height + 'px'; + card.style.minWidth = initialRect.width + 'px'; + card.style.flexShrink = '0'; + card.style.zIndex = '10000'; + }, 500); + }); + header.addEventListener('mouseup', function () { + clearTimeout(dragTimer); + }); + } + + document.addEventListener('mousemove', function (e) { + if (isDragging) { + card.style.left = (e.pageX - offsetX) + 'px'; + card.style.top = (e.pageY - offsetY) + 'px'; } - if (container) { - ensureTopZonePlaceholder(); - container.appendChild(card); - droppedInTop = true; - - container.style.position = 'relative'; - card.style.position = 'absolute'; - card.style.left = '0px'; - - // Animate vertical slide/fade. - card.style.transform = 'translateY(30px)'; - card.style.opacity = '0'; - - card.offsetWidth; // Force reflow. - - requestAnimationFrame(() => { - card.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; - card.style.transform = 'translateY(0)'; - card.style.opacity = '1'; - }); - - setTimeout(() => { - card.style.position = ''; - container.style.position = ''; - card.style.transition = ''; - card.style.transform = ''; - card.style.opacity = ''; - card.style.width = ''; - }, 310); + }); + + document.addEventListener('mouseup', function (e) { + if (isDragging) { + isDragging = false; + card.style.pointerEvents = ''; + card.classList.remove('dragging'); + removeTopZoneHighlight(); + + const sidebar = document.getElementById('sidebarDropArea'); + if (sidebar) { + sidebar.classList.remove('highlight'); + sidebar.style.height = ''; + } + + let droppedInSidebar = false; + let droppedInTop = false; + + // Check if dropped in sidebar drop zone. + const sidebarElem = document.getElementById('sidebarDropArea'); + if (sidebarElem) { + const rect = sidebarElem.getBoundingClientRect(); + const dropZoneBottom = rect.top + 800; // Virtual drop zone height. + if ( + e.clientX >= rect.left && + e.clientX <= rect.right && + e.clientY >= rect.top && + e.clientY <= dropZoneBottom + ) { + insertCardInSidebar(card, e); + droppedInSidebar = true; + } + } + // If not dropped in sidebar, check the top drop zone. + const topRow = document.getElementById('uploadFolderRow'); + if (!droppedInSidebar && topRow) { + const rect = topRow.getBoundingClientRect(); + if ( + e.clientX >= rect.left && + e.clientX <= rect.right && + e.clientY >= rect.top && + e.clientY <= rect.bottom + ) { + let container; + if (card.id === 'uploadCard') { + container = document.getElementById('leftCol'); + } else if (card.id === 'folderManagementCard') { + container = document.getElementById('rightCol'); + } + if (container) { + ensureTopZonePlaceholder(); + updateTopZoneLayout(); + container.appendChild(card); + droppedInTop = true; + // Use computed style to determine container's width. + const containerWidth = parseFloat(window.getComputedStyle(container).width); + card.style.width = "363px"; + // Animate the card sliding in. + animateVerticalSlide(card); + // After animation completes, clear the inline width. + setTimeout(() => { + card.style.removeProperty('width'); + }, 210); + } + } + } + + // If dropped in neither area, return card to its original container. + if (!droppedInSidebar && !droppedInTop) { + const orig = document.getElementById(card.dataset.originalContainerId); + if (orig) { + orig.appendChild(card); + card.style.removeProperty('width'); + } + } + + // Clear inline styles from dragging. + [ + 'position', + 'left', + 'top', + 'z-index', + 'height', + 'min-width', + 'flex-shrink', + 'transition', + 'transform', + 'opacity' + ].forEach(prop => card.style.removeProperty(prop)); + + // For sidebar drops, force width to 100%. + if (droppedInSidebar) { + card.style.width = '100%'; + } + + updateTopZoneLayout(); + updateSidebarVisibility(); } - } - } - - if (droppedInSidebar || droppedInTop) { - card.style.position = ''; - card.style.left = ''; - card.style.top = ''; - card.style.zIndex = ''; - } else { - const orig = document.getElementById(card.dataset.originalContainerId); - if (orig) { - orig.appendChild(card); - card.style.position = ''; - card.style.left = ''; - card.style.top = ''; - card.style.zIndex = ''; - card.style.width = ''; - } - } - updateTopZoneLayout(); - updateSidebarVisibility(); - } + }); }); - }); } - + if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', run); + document.addEventListener('DOMContentLoaded', run); } else { - run(); + run(); } } \ No newline at end of file diff --git a/getConfig.php b/getConfig.php new file mode 100644 index 0000000..a10a439 --- /dev/null +++ b/getConfig.php @@ -0,0 +1,30 @@ + 'Failed to decrypt configuration.']); + exit; + } + echo $decryptedContent; +} else { + echo json_encode([ + 'oidc' => [ + 'providerUrl' => 'https://your-oidc-provider.com', + 'clientId' => 'YOUR_CLIENT_ID', + 'clientSecret' => 'YOUR_CLIENT_SECRET', + 'redirectUri' => 'https://yourdomain.com/auth.php?oidc=callback' + ], + 'loginOptions' => [ + 'disableFormLogin' => false, + 'disableBasicAuth' => false, + 'disableOIDCLogin' => false + ] + ]); +} +?> \ No newline at end of file diff --git a/index.html b/index.html index 2ab88e0..fdccbe1 100644 --- a/index.html +++ b/index.html @@ -123,10 +123,10 @@ -