totp adjustments

This commit is contained in:
Ryan
2025-04-05 23:42:52 -04:00
committed by GitHub
parent 5100e8bf3b
commit 8d370fd1bb
4 changed files with 47 additions and 66 deletions

View File

@@ -186,8 +186,8 @@ if (!preg_match('/^[A-Za-z0-9_\- ]+$/', $username)) {
$user = authenticate($username, $password);
if ($user !== false) {
if (!empty($user['totp_secret'])) {
if (empty($data['totp_code'])) {
http_response_code(401);
// If TOTP code is missing or malformed, indicate that TOTP is required.
if (empty($data['totp_code']) || !preg_match('/^\d{6}$/', $data['totp_code'])) {
echo json_encode([
"totp_required" => true,
"message" => "TOTP code required"
@@ -197,7 +197,6 @@ if ($user !== false) {
$tfa = new \RobThree\Auth\TwoFactorAuth('FileRise');
$providedCode = trim($data['totp_code']);
if (!$tfa->verifyCode($user['totp_secret'], $providedCode)) {
http_response_code(401);
echo json_encode(["error" => "Invalid TOTP code"]);
exit();
}
@@ -232,10 +231,13 @@ if ($user !== false) {
];
$encryptedContent = encryptData(json_encode($persistentTokens, JSON_PRETTY_PRINT), $encryptionKey);
file_put_contents($persistentTokensFile, $encryptedContent, LOCK_EX);
// Define $secure based on whether HTTPS is enabled
$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
setcookie('remember_me_token', $token, $expiry, '/', '', $secure, true);
}
echo json_encode([
"status" => "ok",
"success" => "Login successful",
"isAdmin" => $_SESSION["isAdmin"],
"folderOnly"=> $_SESSION["folderOnly"],

View File

@@ -98,14 +98,14 @@ function loadAdminConfigFunc() {
localStorage.setItem("disableFormLogin", config.loginOptions.disableFormLogin);
localStorage.setItem("disableBasicAuth", config.loginOptions.disableBasicAuth);
localStorage.setItem("disableOIDCLogin", config.loginOptions.disableOIDCLogin);
localStorage.setItem("globalOtpauthUrl", config.globalOtpauthUrl || "otpauth://totp/FileRise?issuer=FileRise");
localStorage.setItem("globalOtpauthUrl", config.globalOtpauthUrl || "otpauth://totp/{label}?secret={secret}&issuer=FileRise");
updateLoginOptionsUIFromStorage();
})
.catch(() => {
localStorage.setItem("disableFormLogin", "false");
localStorage.setItem("disableBasicAuth", "false");
localStorage.setItem("disableOIDCLogin", "false");
localStorage.setItem("globalOtpauthUrl", "otpauth://totp/FileRise?issuer=FileRise");
localStorage.setItem("globalOtpauthUrl", "otpauth://totp/{label}?secret={secret}&issuer=FileRise");
updateLoginOptionsUIFromStorage();
});
}
@@ -225,15 +225,15 @@ function checkAuthentication(showLoginToast = true) {
function submitLogin(data) {
setLastLoginData(data);
window.__lastLoginData = data;
sendRequest("auth.php", "POST", data, { "X-CSRF-Token": window.csrfToken })
.then(response => {
if (response.success) {
sessionStorage.setItem("welcomeMessage", "Welcome back, " + data.username + "!");
window.location.reload();
} else if (response.totp_required) {
openTOTPLoginModal();
} else if (response.error && response.error.includes("Too many failed login attempts")) {
showToast(response.error);
sendRequest("auth.php", "POST", data, { "X-CSRF-Token": window.csrfToken })
.then(response => {
if (response.success || response.status === "ok") {
sessionStorage.setItem("welcomeMessage", "Welcome back, " + data.username + "!");
window.location.reload();
} else if (response.totp_required) {
openTOTPLoginModal();
} else if (response.error && response.error.includes("Too many failed login attempts")) {
showToast(response.error);
const loginButton = document.getElementById("authForm").querySelector("button[type='submit']");
if (loginButton) {
loginButton.disabled = true;

View File

@@ -49,15 +49,11 @@ export function openTOTPLoginModal() {
totpInput.addEventListener("input", function () {
const code = this.value.trim();
if (code.length === 6) {
// FORM-BASED LOGIN
if (lastLoginData) {
totpLoginModal.style.display = "none";
lastLoginData.totp_code = code;
window.submitLogin(lastLoginData);
// BASIC-AUTH / OIDC LOGIN
} else {
// keep modal open until we know the result
fetch("totp_verify.php", {
method: "POST",
credentials: "include",
@@ -67,23 +63,23 @@ export function openTOTPLoginModal() {
},
body: JSON.stringify({ totp_code: code })
})
.then(res => res.json())
.then(json => {
if (json.success) {
window.location.href = "index.html";
} else {
showToast(json.error || json.message || "TOTP verification failed");
this.value = "";
totpLoginModal.style.display = "flex";
totpInput.focus();
}
})
.catch(() => {
showToast("TOTP verification failed");
.then(res => res.json())
.then(json => {
if (json.status === "ok") {
window.location.href = "index.html";
} else {
showToast(json.message || "TOTP verification failed");
this.value = "";
totpLoginModal.style.display = "flex";
totpInput.focus();
});
}
})
.catch(() => {
showToast("TOTP verification failed");
this.value = "";
totpLoginModal.style.display = "flex";
totpInput.focus();
});
}
}
});
@@ -92,7 +88,6 @@ export function openTOTPLoginModal() {
const modalContent = totpLoginModal.firstElementChild;
modalContent.style.background = modalBg;
modalContent.style.color = textColor;
// reset input if reopening
const totpInput = document.getElementById("totpLoginInput");
if (totpInput) {
totpInput.value = "";
@@ -191,10 +186,10 @@ export function openUserPanel() {
}
export function openTOTPModal() {
let totpModal = document.getElementById("totpModal");
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 = `
let totpModal = document.getElementById("totpModal");
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;
@@ -232,19 +227,17 @@ export function openTOTPModal() {
</div>
`;
document.body.appendChild(totpModal);
// Bind the X button to call closeTOTPModal with disable=true
document.getElementById("closeTOTPModal").addEventListener("click", () => {
closeTOTPModal(true);
});
// Add event listener for TOTP confirmation
document.getElementById("confirmTOTPBtn").addEventListener("click", function () {
const code = document.getElementById("totpConfirmInput").value.trim();
if (code.length !== 6) {
showToast("Please enter a valid 6-digit code.");
return;
}
// Call the endpoint to verify the TOTP code
fetch("totp_verify.php", {
method: "POST",
credentials: "include",
@@ -254,17 +247,16 @@ export function openTOTPModal() {
},
body: JSON.stringify({ totp_code: code })
})
.then(r => r.json())
.then(result => {
if (result.success) {
showToast("TOTP successfully enabled.");
// On success, close the modal without disabling
closeTOTPModal(false);
} else {
showToast("TOTP verification failed: " + (result.error || "Invalid code."));
}
})
.catch(() => { showToast("Error verifying TOTP code."); });
.then(r => r.json())
.then(result => {
if (result.status === 'ok') {
showToast("TOTP successfully enabled.");
closeTOTPModal(false);
} else {
showToast("TOTP verification failed: " + (result.message || "Invalid code."));
}
})
.catch(() => { showToast("Error verifying TOTP code."); });
});
} else {
totpModal.style.display = "flex";
@@ -508,7 +500,7 @@ export function openAdminPanel() {
document.getElementById("oidcClientId").value = window.currentOIDCConfig.clientId;
document.getElementById("oidcClientSecret").value = window.currentOIDCConfig.clientSecret;
document.getElementById("oidcRedirectUri").value = window.currentOIDCConfig.redirectUri;
document.getElementById("globalOtpauthUrl").value = window.currentOIDCConfig.globalOtpauthUrl || 'otpauth://totp/FileRise?issuer=FileRise';
document.getElementById("globalOtpauthUrl").value = window.currentOIDCConfig.globalOtpauthUrl || 'otpauth://totp/{label}?secret={secret}&issuer=FileRise';
document.getElementById("disableFormLogin").checked = config.loginOptions.disableFormLogin === true;
document.getElementById("disableBasicAuth").checked = config.loginOptions.disableBasicAuth === true;
document.getElementById("disableOIDCLogin").checked = config.loginOptions.disableOIDCLogin === true;
@@ -529,7 +521,7 @@ export function openAdminPanel() {
document.getElementById("oidcClientId").value = window.currentOIDCConfig.clientId;
document.getElementById("oidcClientSecret").value = window.currentOIDCConfig.clientSecret;
document.getElementById("oidcRedirectUri").value = window.currentOIDCConfig.redirectUri;
document.getElementById("globalOtpauthUrl").value = window.currentOIDCConfig.globalOtpauthUrl || 'otpauth://totp/FileRise?issuer=FileRise';
document.getElementById("globalOtpauthUrl").value = window.currentOIDCConfig.globalOtpauthUrl || 'otpauth://totp/{label}?secret={secret}&issuer=FileRise';
document.getElementById("disableFormLogin").checked = localStorage.getItem("disableFormLogin") === "true";
document.getElementById("disableBasicAuth").checked = localStorage.getItem("disableBasicAuth") === "true";
document.getElementById("disableOIDCLogin").checked = localStorage.getItem("disableOIDCLogin") === "true";

View File

@@ -4,19 +4,6 @@
require_once 'vendor/autoload.php';
require_once 'config.php';
// Secure session cookie
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => '', // your domain
'secure' => true, // only over HTTPS
'httponly' => true,
'samesite' => 'Lax'
]);
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
// JSON + CSP
header('Content-Type: application/json');
header("Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self';");