fix: multiple critical bugs in frontend

- sidebar: fix library/tag selection event handlers not firing (callbacks never invoked)
- sidebar: fix handleSelectLibrary always passing empty string instead of library id
- dashboard: fix tag filter not persisting when navigating from document view
- app: fix XSS vulnerability in showToast (API error messages not escaped)
- app: fix XSS vulnerability in confirmDelete modal message
- document: fix path traversal risk in export filename
This commit is contained in:
Hiro
2026-03-28 12:06:16 +00:00
parent af7f639c20
commit 461a17bc45
4 changed files with 80 additions and 43 deletions

View File

@@ -8,8 +8,8 @@ export async function renderDashboard(app) {
let libraries = [];
let tags = [];
let searchQuery = '';
let selectedTag = null;
let selectedLibrary = null;
let selectedTag = app.state.selectedTag || null;
let selectedLibrary = app.state.selectedLibrary || null;
try {
[documents, libraries, tags] = await Promise.all([
@@ -24,6 +24,32 @@ export async function renderDashboard(app) {
const appEl = document.getElementById('app');
function render() {
// Store callbacks for sidebar event handlers
const sidebarCallbacks = {
onSelectLibrary: (id) => {
selectedLibrary = id;
selectedTag = null;
app.state.selectedLibrary = id;
app.state.selectedTag = null;
render();
},
onSelectTag: (tag) => {
selectedTag = tag;
selectedLibrary = null;
app.state.selectedTag = tag;
app.state.selectedLibrary = null;
render();
},
onHome: () => {
selectedTag = null;
selectedLibrary = null;
app.state.selectedTag = null;
app.state.selectedLibrary = null;
render();
}
};
window.__sidebarCallbacks = sidebarCallbacks;
let filteredDocs = documents;
if (searchQuery) {
@@ -64,21 +90,7 @@ export async function renderDashboard(app) {
tags,
selectedLibrary,
selectedTag,
onSelectLibrary: (id) => {
selectedLibrary = id;
selectedTag = null;
render();
},
onSelectTag: (tag) => {
selectedTag = tag;
selectedLibrary = null;
render();
},
onHome: () => {
selectedTag = null;
selectedLibrary = null;
render();
}
...sidebarCallbacks
})}
<main class="main-content">
<div class="content-header">