Skip to content

Commit 2d8aad1

Browse files
committed
Lock down auth surfaces and finish audit cleanup - PR_26157_017-auth-lockdown-and-audit-cleanup
1 parent 80d22a4 commit 2d8aad1

40 files changed

Lines changed: 400 additions & 305 deletions

admin/db-viewer.html

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
<div class="kicker">Admin Only / Mock DB</div>
2020
<h1>Mock DB</h1>
2121
<p class="lede">Read-only mock DB dump for project tables, relationships, and data diagnostics.</p>
22-
<p class="status" role="status" data-session-user-header>Session user: User 1</p>
2322
</div>
2423
</section>
2524
<section class="section">
@@ -30,19 +29,6 @@ <h1>Mock DB</h1>
3029
<h2>Mock DB</h2>
3130
</div>
3231
<div class="accordion-stack">
33-
<details class="vertical-accordion" open>
34-
<summary>Session User</summary>
35-
<div class="accordion-body content-stack">
36-
<div class="action-group" role="group" aria-label="Mock DB session user controls" data-session-user-controls>
37-
<button class="btn btn--compact" type="button" data-session-user-button="guest">Guest</button>
38-
<button class="btn btn--compact" type="button" data-session-user-button="user1">User 1</button>
39-
<button class="btn btn--compact" type="button" data-session-user-button="user2">User 2</button>
40-
<button class="btn btn--compact" type="button" data-session-user-button="user3">User 3</button>
41-
<button class="btn btn--compact" type="button" data-session-user-button="admin">Admin</button>
42-
</div>
43-
<p class="status" role="status" data-session-user-summary>Session user: User 1</p>
44-
</div>
45-
</details>
4632
<details class="vertical-accordion" open>
4733
<summary>Scope</summary>
4834
<div class="accordion-body content-stack">

admin/db-viewer.js

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import { createProjectWorkspacePaletteRepository } from "../toolbox/colors/palet
44
import {
55
getAllPersistedMockDbSnapshot,
66
clearMockDbTables,
7-
getMockDbSessionUser,
87
getStandaloneMockDbTables,
98
seedMockDbTables,
10-
setMockDbSessionUser,
119
} from "../src/engine/persistence/mock-db-store.js";
1210

1311
const AUDIT_FIELDS = ["createdAt", "updatedAt", "createdBy", "updatedBy"];
@@ -35,9 +33,6 @@ class AdminDbViewer {
3533
this.status = documentRef.querySelector("[data-admin-db-status]");
3634
this.diagnostics = documentRef.querySelector("[data-admin-db-diagnostics]");
3735
this.relationships = documentRef.querySelector("[data-admin-db-relationships]");
38-
this.sessionSummary = documentRef.querySelector("[data-session-user-summary]");
39-
this.sessionHeader = documentRef.querySelector("[data-session-user-header]");
40-
this.sessionUserControls = documentRef.querySelector("[data-session-user-controls]");
4136
this.tablesRoot = documentRef.querySelector("[data-admin-db-tables]");
4237
}
4338

@@ -58,16 +53,6 @@ class AdminDbViewer {
5853
this.activeFilter = button.dataset.adminDbFilter || "all";
5954
this.render();
6055
});
61-
this.sessionUserControls?.addEventListener("click", (event) => {
62-
const button = event.target.closest("[data-session-user-button]");
63-
if (!button) {
64-
return;
65-
}
66-
setMockDbSessionUser(button.dataset.sessionUserButton || "guest");
67-
this.createRepositories();
68-
this.projectJourneyRepository.openProject("demo-project");
69-
this.render();
70-
});
7156
this.clearButton?.addEventListener("click", () => {
7257
const snapshot = getAllPersistedMockDbSnapshot();
7358
if (snapshot.cleared) {
@@ -303,26 +288,6 @@ class AdminDbViewer {
303288
});
304289
}
305290

306-
renderSessionUser() {
307-
const sessionUser = getMockDbSessionUser();
308-
if (this.sessionHeader) {
309-
this.sessionHeader.textContent = `Session user: ${sessionUser.label}`;
310-
}
311-
if (this.sessionSummary) {
312-
this.sessionSummary.textContent = `Selected session user: ${sessionUser.label}.`;
313-
}
314-
this.document.querySelectorAll("[data-session-user-button]").forEach((button) => {
315-
const selected = button.dataset.sessionUserButton === sessionUser.id;
316-
button.classList.toggle("primary", selected);
317-
button.setAttribute("aria-pressed", String(selected));
318-
if (selected) {
319-
button.setAttribute("aria-current", "true");
320-
} else {
321-
button.removeAttribute("aria-current");
322-
}
323-
});
324-
}
325-
326291
auditFindings(tables) {
327292
const findings = [];
328293
Object.entries(tables).forEach(([tableName, records]) => {
@@ -526,7 +491,6 @@ class AdminDbViewer {
526491
.map((tableName) => [tableName, snapshot.tables[tableName]]),
527492
);
528493
this.renderFilters(snapshot.groups);
529-
this.renderSessionUser();
530494
this.renderClearSeedButton(snapshot.cleared);
531495
this.renderDiagnostics(snapshot.tables, snapshot.groups);
532496
this.renderRelationships(snapshot.tables);

assets/theme-v2/js/gamefoundry-partials.js

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,22 +121,18 @@
121121
const localSessionUsers = {
122122
user1: {
123123
displayName: "User 1",
124-
roleSlugs: ["user"],
125124
userKey: makeMockUlid(51)
126125
},
127126
user2: {
128127
displayName: "User 2",
129-
roleSlugs: ["user"],
130128
userKey: makeMockUlid(52)
131129
},
132130
user3: {
133131
displayName: "User 3",
134-
roleSlugs: ["user"],
135132
userKey: makeMockUlid(53)
136133
},
137134
admin: {
138135
displayName: "Admin",
139-
roleSlugs: ["user", "admin"],
140136
userKey: makeMockUlid(54)
141137
}
142138
};
@@ -203,36 +199,38 @@
203199
}
204200
}
205201

206-
function rolesForUser(state, userKey, fallbackRoleSlugs) {
202+
function rolesForUser(state, userKey) {
207203
const rows = state?.tables?.user_roles || [];
208204
const roles = new Map((state?.tables?.roles || []).map(function (role) {
209205
return [role.key, role.roleSlug || role.name];
210206
}));
211-
const resolved = rows
207+
return rows
212208
.filter(function (row) {
213209
return row.userKey === userKey && roles.has(row.roleKey);
214210
})
215211
.map(function (row) {
216212
return roles.get(row.roleKey);
217213
})
218214
.filter(Boolean);
219-
return resolved.length ? resolved : fallbackRoleSlugs;
220215
}
221216

222217
function localDevLoginState() {
223218
if (selectedSessionModeId() === "dev") {
224219
return {
225220
authenticated: false,
221+
diagnostic: "",
226222
displayName: "Login",
227223
mode: "dev",
228224
roleSlugs: []
229225
};
230226
}
231227

232-
const session = localSessionUsers[selectedLocalSessionId()];
228+
const sessionId = selectedLocalSessionId();
229+
const session = localSessionUsers[sessionId];
233230
if (!session) {
234231
return {
235232
authenticated: false,
233+
diagnostic: "",
236234
displayName: "Login",
237235
mode: "local",
238236
roleSlugs: []
@@ -243,6 +241,9 @@
243241
if (!state) {
244242
return {
245243
authenticated: false,
244+
diagnostic: sessionId === "guest"
245+
? ""
246+
: "Persisted Memory DB users and roles are not seeded. Open Login and choose Local to seed local users.",
246247
displayName: "Login",
247248
mode: "local",
248249
roleSlugs: []
@@ -255,6 +256,18 @@
255256
if (!user) {
256257
return {
257258
authenticated: false,
259+
diagnostic: `Selected Local user ${session.displayName} is missing from persisted Memory DB users.`,
260+
displayName: "Login",
261+
mode: "local",
262+
roleSlugs: []
263+
};
264+
}
265+
266+
const roleSlugs = rolesForUser(state, session.userKey);
267+
if (!roleSlugs.length) {
268+
return {
269+
authenticated: false,
270+
diagnostic: `Selected Local user ${session.displayName} has no persisted Memory DB roles.`,
258271
displayName: "Login",
259272
mode: "local",
260273
roleSlugs: []
@@ -263,9 +276,10 @@
263276

264277
return {
265278
authenticated: true,
279+
diagnostic: "",
266280
displayName: user?.displayName || session.displayName,
267281
mode: "local",
268-
roleSlugs: rolesForUser(state, session.userKey, [])
282+
roleSlugs
269283
};
270284
}
271285

@@ -377,7 +391,10 @@
377391
status.className = "status";
378392
status.setAttribute("role", "status");
379393
status.dataset.sessionAccessStatus = "";
380-
status.textContent = `Blocked ${pagePath}. Current session: ${loginState.displayName}.`;
394+
status.textContent = [
395+
`Blocked ${pagePath}. Current session: ${loginState.displayName}.`,
396+
loginState.diagnostic ? `Login/session diagnostic: ${loginState.diagnostic}` : ""
397+
].filter(Boolean).join(" ");
381398
const link = document.createElement("a");
382399
link.className = "btn primary";
383400
link.href = routeHref("login") + "?returnTo=" + encodeURIComponent(pagePath);
@@ -398,6 +415,7 @@
398415
const allowed = canUseProtectedPage(requirement, loginState);
399416
window.GameFoundrySessionGuard = {
400417
blocked: !allowed,
418+
diagnostic: loginState.diagnostic || "",
401419
mode: loginState.mode,
402420
pagePath,
403421
requirement: requirement?.role || ""
@@ -443,6 +461,26 @@
443461
updateVisibility();
444462
}
445463

464+
function logoutCurrentSession(event) {
465+
event.preventDefault();
466+
try {
467+
window.localStorage.removeItem(mockDbSessionStorageKey);
468+
window.dispatchEvent(new CustomEvent("gamefoundry:mock-db-session-user-changed", {
469+
detail: {
470+
authenticated: false,
471+
id: "guest"
472+
}
473+
}));
474+
} catch {}
475+
refreshHeaderLoginState();
476+
}
477+
478+
function wireAccountLogout(root) {
479+
root.querySelectorAll("[data-account-logout]").forEach(function (link) {
480+
link.addEventListener("click", logoutCurrentSession);
481+
});
482+
}
483+
446484
async function partialElement(partialName) {
447485
const partialPath = partials[partialName];
448486
if (!partialPath) return null;
@@ -459,6 +497,7 @@
459497
if (partialName === "header-nav") {
460498
applyLocalDevLoginState(element);
461499
markActiveNavigation(element);
500+
wireAccountLogout(element);
462501
} else if (partialName === "footer") {
463502
wireReturnToTop(element);
464503
}

assets/theme-v2/partials/header-nav.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
<div class="sub-menu">
102102
<a data-nav-link data-route="account" href="account/index.html">Account Home</a>
103103
<a data-nav-link data-route="account-achievements" href="account/achievements.html">Achievements</a>
104+
<a data-account-logout data-route="login" href="login.html">Logout</a>
104105
<a data-nav-link data-route="account-preferences" href="account/preferences.html">Preferences</a>
105106
<a data-nav-link data-route="account-profile" href="account/profile.html">Profile</a>
106107
<a data-nav-link data-route="account-security" href="account/security.html">Security</a>

0 commit comments

Comments
 (0)