hopefully get this working first try

This commit is contained in:
KingKDot
2026-03-07 15:14:00 -06:00
parent d26668df78
commit 4053293ccb
12 changed files with 496 additions and 12 deletions
+110
View File
@@ -36,8 +36,19 @@ const securityRequireLowercaseInput = document.getElementById("security-require-
const securityRequireNumberInput = document.getElementById("security-require-number");
const securityRequireSymbolInput = document.getElementById("security-require-symbol");
const tlsForm = document.getElementById("tls-form");
const tlsPermissionNote = document.getElementById("tls-permission-note");
const tlsSaveBtn = document.getElementById("tls-save-btn");
const tlsCertbotEnabledInput = document.getElementById("tls-certbot-enabled");
const tlsCertbotLivePathInput = document.getElementById("tls-certbot-live-path");
const tlsCertbotDomainInput = document.getElementById("tls-certbot-domain");
const tlsCertbotCertFileInput = document.getElementById("tls-certbot-cert-file");
const tlsCertbotKeyFileInput = document.getElementById("tls-certbot-key-file");
const tlsCertbotCaFileInput = document.getElementById("tls-certbot-ca-file");
let currentUser = null;
let securityConfig = null;
let tlsConfig = null;
function showMessage(text, type = "ok") {
if (!messageEl) return;
@@ -123,6 +134,23 @@ function setSecurityFormDisabled(disabled) {
}
}
function setTlsFormDisabled(disabled) {
const controls = [
tlsCertbotEnabledInput,
tlsCertbotLivePathInput,
tlsCertbotDomainInput,
tlsCertbotCertFileInput,
tlsCertbotKeyFileInput,
tlsCertbotCaFileInput,
tlsSaveBtn,
];
for (const control of controls) {
if (!control) continue;
control.disabled = disabled;
}
}
function applySecurityForm() {
if (!securityConfig) return;
securitySessionTtlInput.value = String(securityConfig.sessionTtlHours || 168);
@@ -169,6 +197,50 @@ async function loadSecurityPolicy() {
setSecurityFormDisabled(false);
}
function applyTlsForm() {
const certbot = tlsConfig?.certbot || {};
tlsCertbotEnabledInput.checked = Boolean(certbot.enabled);
tlsCertbotLivePathInput.value = certbot.livePath || "/etc/letsencrypt/live";
tlsCertbotDomainInput.value = certbot.domain || "";
tlsCertbotCertFileInput.value = certbot.certFileName || "fullchain.pem";
tlsCertbotKeyFileInput.value = certbot.keyFileName || "privkey.pem";
tlsCertbotCaFileInput.value = certbot.caFileName || "chain.pem";
}
async function loadTlsSettings() {
if (!currentUser) return;
if (!isAdmin(currentUser.role)) {
tlsPermissionNote.classList.remove("hidden");
setTlsFormDisabled(true);
tlsConfig = {
certbot: {
enabled: false,
livePath: "/etc/letsencrypt/live",
domain: "",
certFileName: "fullchain.pem",
keyFileName: "privkey.pem",
caFileName: "chain.pem",
},
};
applyTlsForm();
return;
}
tlsPermissionNote.classList.add("hidden");
const res = await fetch("/api/settings/tls", { credentials: "include" });
if (!res.ok) {
showMessage("Failed to load TLS settings.", "error");
setTlsFormDisabled(true);
return;
}
const data = await res.json().catch(() => ({}));
tlsConfig = data.tls || null;
applyTlsForm();
setTlsFormDisabled(false);
}
function loadPrefs() {
prefNotificationsInput.checked = getNotificationsEnabled();
const refreshSeconds = Number(localStorage.getItem(PREF_REFRESH_KEY) || 8);
@@ -277,6 +349,42 @@ async function saveSecurityPolicy(event) {
showMessage("Security policy updated.");
}
async function saveTlsSettings(event) {
event.preventDefault();
if (!isAdmin(currentUser?.role)) {
showMessage("Admin role required.", "error");
return;
}
const payload = {
certbot: {
enabled: tlsCertbotEnabledInput.checked,
livePath: String(tlsCertbotLivePathInput.value || "").trim(),
domain: String(tlsCertbotDomainInput.value || "").trim(),
certFileName: String(tlsCertbotCertFileInput.value || "").trim(),
keyFileName: String(tlsCertbotKeyFileInput.value || "").trim(),
caFileName: String(tlsCertbotCaFileInput.value || "").trim(),
},
};
const res = await fetch("/api/settings/tls", {
method: "PUT",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify(payload),
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
showMessage(data.error || "Failed to save TLS settings.", "error");
return;
}
tlsConfig = data.tls || payload;
applyTlsForm();
showMessage("TLS settings updated. Restart server to apply.");
}
async function loadBannedIps() {
if (!currentUser) return;
@@ -368,11 +476,13 @@ async function init() {
await loadCurrentUser();
loadPrefs();
await loadSecurityPolicy();
await loadTlsSettings();
await loadBannedIps();
passwordForm.addEventListener("submit", updatePassword);
prefsForm.addEventListener("submit", savePrefs);
securityForm.addEventListener("submit", saveSecurityPolicy);
tlsForm.addEventListener("submit", saveTlsSettings);
refreshBansBtn.addEventListener("click", loadBannedIps);
bansTableBody.addEventListener("click", handleUnbanClick);
} catch (error) {
+72
View File
@@ -195,6 +195,78 @@
</button>
</form>
<form id="tls-form" class="space-y-3 pt-1 border-t border-slate-800 pt-4">
<div>
<h3 class="font-medium">TLS Certificates</h3>
<p class="text-xs text-slate-400">Admin-only TLS source configuration. Changes apply after server restart.</p>
</div>
<div id="tls-permission-note" class="hidden rounded-lg border border-amber-800 bg-amber-900/20 text-amber-200 px-3 py-2 text-sm">
Only admins can update TLS settings.
</div>
<label class="flex items-center gap-2 text-sm">
<input id="tls-certbot-enabled" type="checkbox" class="h-4 w-4" />
<span>Use certbot certificates in production runtime (NODE_ENV=production)</span>
</label>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<label class="block sm:col-span-2">
<span class="text-sm text-slate-300">Certbot live base path</span>
<input
id="tls-certbot-live-path"
type="text"
placeholder="/etc/letsencrypt/live"
class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</label>
<label class="block sm:col-span-2">
<span class="text-sm text-slate-300">Certbot domain folder</span>
<input
id="tls-certbot-domain"
type="text"
placeholder="example.com"
class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</label>
<label class="block">
<span class="text-sm text-slate-300">Cert file name</span>
<input
id="tls-certbot-cert-file"
type="text"
placeholder="fullchain.pem"
class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</label>
<label class="block">
<span class="text-sm text-slate-300">Key file name</span>
<input
id="tls-certbot-key-file"
type="text"
placeholder="privkey.pem"
class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</label>
<label class="block sm:col-span-2">
<span class="text-sm text-slate-300">CA chain file name</span>
<input
id="tls-certbot-ca-file"
type="text"
placeholder="chain.pem"
class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-sky-500"
/>
</label>
</div>
<button
type="submit"
id="tls-save-btn"
class="px-4 py-2 rounded-lg bg-cyan-700 hover:bg-cyan-600 transition-colors text-white font-medium"
>
<i class="fa-solid fa-certificate mr-2"></i>Save TLS Settings
</button>
</form>
<p id="settings-message" class="hidden text-sm rounded-lg px-3 py-2"></p>
</div>