[feat](trx-frontend-http): add restricted Guest role
CI / lint (pull_request) Successful in 2m24s
CI / test (pull_request) Successful in 8m16s
CI / frontend (pull_request) Successful in 4m17s
CI / reuse (pull_request) Successful in 5s

Assisted-By: Codex (GPT-5)
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
sjg
2026-08-11 16:04:51 +02:00
parent 5e9dae02c7
commit 44870bc941
17 changed files with 240 additions and 66 deletions
@@ -1,17 +1,19 @@
import {
AUTH_ADMIN_ROLES,
AUTH_ROLES,
AUTH_ROLE_LABELS,
changeOwnPassword,
createUser,
deleteUser,
fetchAuthSession,
hasAccountControls,
hasAuthRole,
listUsers,
login,
logout,
normalizeAuthRoles,
updateUser
} from "./chunk-BB2X7SND.js";
} from "./chunk-FT2RH7BL.js";
// src/webgl-renderer.ts
(function initTrxWebGl(global) {
@@ -1846,6 +1848,19 @@ function buildRoleChoices(selected) {
element.append(label);
return { input, value };
});
inputs.forEach(({ input, value }) => {
input.addEventListener("change", () => {
if (!input.checked) return;
if (value === "guest") {
inputs.forEach((choice) => {
if (choice.value !== "guest") choice.input.checked = false;
});
} else {
const guest = inputs.find((choice) => choice.value === "guest");
if (guest) guest.input.checked = false;
}
});
});
return { element, inputs };
}
async function checkAuthStatus() {
@@ -1932,7 +1947,13 @@ function updateAuthUI() {
return;
}
if (authRoles.length > 0) {
if (accountTab) accountTab.style.display = "";
const canManageAccount = hasAccountControls(authRoles);
if (accountTab) accountTab.style.display = canManageAccount ? "" : "none";
if (!canManageAccount && accountTab?.classList.contains("active")) {
const panel = document.getElementById("subtab-settings-account");
if (panel) panel.style.display = "none";
document.querySelector('[data-subtab="settings-scheduler"]')?.click();
}
if (badge) badge.style.display = "block";
if (badgeRole) badgeRole.textContent = `${authUsername || "local"}${authRoles.map((role) => AUTH_ROLE_LABELS[role]).join(", ")}`;
if (headerAuthBtn2) {
@@ -5974,7 +5995,7 @@ async function initializeApp() {
const authStatus = await checkAuthStatus();
authEnabled = !authStatus.auth_disabled;
if (!authEnabled) {
setAuthRoles(AUTH_ROLES);
setAuthRoles(AUTH_ADMIN_ROLES);
hideAuthGate();
updateAuthUI();
connect();
@@ -6047,10 +6068,15 @@ async function refreshUserManagement() {
enabledLabel.append(enabled, " Enabled");
const isOnlyAdmin = user.enabled && hasAuthRole(user.roles, "administrator") && enabledAdminCount === 1;
const administratorInput = roleInputs.find((item) => item.value === "administrator")?.input;
const guestInput = roleInputs.find((item) => item.value === "guest")?.input;
if (isOnlyAdmin && administratorInput) {
administratorInput.disabled = true;
administratorInput.title = "The final administrator cannot be demoted";
}
if (isOnlyAdmin && guestInput) {
guestInput.disabled = true;
guestInput.title = "The final administrator cannot become a Guest";
}
if (isOnlyAdmin) {
enabled.disabled = true;
enabled.title = "The final enabled administrator cannot be disabled";
@@ -1,6 +1,6 @@
import {
hasAuthRole
} from "./chunk-BB2X7SND.js";
} from "./chunk-FT2RH7BL.js";
import {
hostState
} from "./chunk-KL66PICH.js";
@@ -1,6 +1,6 @@
import {
hasAuthRole
} from "./chunk-BB2X7SND.js";
} from "./chunk-FT2RH7BL.js";
import {
hostCore,
hostState
@@ -1,6 +1,8 @@
// src/api/auth.ts
var AUTH_ROLES = ["read", "control", "write", "administrator"];
var AUTH_ROLES = ["guest", "read", "control", "write", "administrator"];
var AUTH_ADMIN_ROLES = AUTH_ROLES.filter((role) => role !== "guest");
var AUTH_ROLE_LABELS = {
guest: "Guest",
read: "Read",
control: "Control",
write: "Write",
@@ -13,7 +15,10 @@ function normalizeAuthRoles(roles) {
return AUTH_ROLES.filter((role) => roles.includes(role));
}
function hasAuthRole(roles, required) {
return roles.includes("administrator") || roles.includes(required) || required === "read" && roles.includes("control");
return roles.includes("administrator") || roles.includes(required) || required === "read" && roles.includes("guest") || required === "read" && roles.includes("control");
}
function hasAccountControls(roles) {
return roles.length > 0 && !roles.includes("guest");
}
function decodeRoles(value, context) {
if (!Array.isArray(value) || !value.every(isAuthRole)) {
@@ -45,7 +50,7 @@ function decodeAuthSession(value) {
}
var authDisabledSession = {
authenticated: true,
roles: ["read", "control", "write", "administrator"],
roles: [...AUTH_ADMIN_ROLES],
auth_disabled: true
};
async function fetchAuthSession() {
@@ -114,9 +119,11 @@ async function logout() {
export {
AUTH_ROLES,
AUTH_ADMIN_ROLES,
AUTH_ROLE_LABELS,
normalizeAuthRoles,
hasAuthRole,
hasAccountControls,
fetchAuthSession,
login,
listUsers,
@@ -1,6 +1,6 @@
import {
hasAuthRole
} from "./chunk-BB2X7SND.js";
} from "./chunk-FT2RH7BL.js";
import {
hostCore,
hostState
@@ -1,6 +1,6 @@
import {
hasAuthRole
} from "./chunk-BB2X7SND.js";
} from "./chunk-FT2RH7BL.js";
import {
hostState
} from "./chunk-KL66PICH.js";