Files
brass-and-sigil/server/wwwroot/modules/whitelist.js
T
Matt Sijbers a1331212cb Initial commit: Brass & Sigil monorepo
Self-hosted Minecraft modpack distribution + administration system.

- launcher/  Avalonia 12 desktop client; single-file win-x64 publish.
             Microsoft auth via XboxAuthNet, manifest+SHA-1 mod sync,
             portable install path, sidecar settings.
- server/    brass-sigil-server daemon (.NET 8, linux-x64). Wraps the
             MC subprocess, embedded Kestrel admin panel with cookie
             auth + rate limiting, RCON bridge, scheduled backups,
             BlueMap CLI integration with player markers + skin proxy,
             friend-side whitelist request flow, world wipe with seed
             selection (keep current / random / custom).
- pack/      pack.lock.json (Modrinth + manual CurseForge entries),
             data-only tweak source under tweaks/, build outputs in
             overrides/ (gitignored).
- scripts/   Build-Pack / Build-Tweaks / Update-Pack / Check-Updates
             plus Deploy-Brass.ps1 unified one-shot deploy with
             version-bump pre-flight and daemon-state detection.
2026-05-05 00:19:05 +01:00

87 lines
3.5 KiB
JavaScript

// Whitelist add / remove via the API; refreshes the panel display shortly after
// each action (server takes ~1-2 s to look up UUID via Mojang and write whitelist.json).
"use strict";
import { api, apiJson, escapeHtml } from "./api.js";
export function setupWhitelistActions(refreshSoon) {
const wlInput = document.getElementById("wlInput");
document.getElementById("wlAdd").addEventListener("click", () => addWhitelisted(refreshSoon));
wlInput.addEventListener("keydown", e => { if (e.key === "Enter") addWhitelisted(refreshSoon); });
// Delegated removal -- list items are re-rendered each tick, no static binding.
document.getElementById("whitelist").addEventListener("click", async e => {
const btn = e.target.closest(".wl-remove");
if (!btn) return;
const name = btn.dataset.name;
if (!name) return;
if (!confirm(`Remove ${name} from whitelist?`)) return;
try {
await apiJson("/api/whitelist/remove", { name });
refreshSoon();
} catch (err) { alert(err.message); }
});
// Pending whitelist requests from friends. Approve adds to whitelist + clears
// the request; Deny just marks denied so the friend's launcher knows.
const reqsList = document.getElementById("wlRequests");
const reqsBlock = document.getElementById("wlRequestsBlock");
const reqsBadge = document.getElementById("wlReqBadge");
reqsList?.addEventListener("click", async e => {
const btn = e.target.closest("button[data-req-action]");
if (!btn) return;
const name = btn.dataset.name;
const action = btn.dataset.reqAction; // "approve" | "deny"
if (!name || !action) return;
if (action === "deny" && !confirm(`Deny ${name}'s request?`)) return;
try {
await apiJson(`/api/whitelist/requests/${action}`, { name });
await refreshRequests();
// Approving fires /whitelist add via stdin -- let the server-side write
// ~1-2 s of grace before re-reading whitelist.json.
if (action === "approve") refreshSoon();
} catch (err) { alert(err.message); }
});
async function refreshRequests() {
if (!reqsList || !reqsBlock || !reqsBadge) return;
let data;
try { data = await api("/api/whitelist/requests"); }
catch { return; }
const reqs = data.requests || [];
if (reqs.length === 0) {
reqsBlock.hidden = true;
reqsBadge.hidden = true;
return;
}
reqsBlock.hidden = false;
reqsBadge.hidden = false;
reqsBadge.textContent = String(reqs.length);
reqsList.innerHTML = reqs.map(r => `
<li>
<div class="wl-req-meta">${escapeHtml(r.username)}</div>
${r.message ? `<div class="wl-req-msg">"${escapeHtml(r.message)}"</div>` : ""}
<div class="wl-req-actions">
<button data-req-action="approve" data-name="${escapeHtml(r.username)}">Approve</button>
<button class="ghost-btn" data-req-action="deny" data-name="${escapeHtml(r.username)}">Deny</button>
</div>
</li>
`).join("");
}
refreshRequests();
setInterval(refreshRequests, 15000);
}
async function addWhitelisted(refreshSoon) {
const inp = document.getElementById("wlInput");
const name = inp.value.trim();
if (!name) return;
try {
await apiJson("/api/whitelist/add", { name });
inp.value = "";
refreshSoon();
} catch (e) { alert(e.message); }
}