diff --git a/src/dashboard.ts b/src/dashboard.ts index 9e4b857e..1e61b975 100644 --- a/src/dashboard.ts +++ b/src/dashboard.ts @@ -20,7 +20,7 @@ initTheme(); function truncatedNoticeHtml(key: string, total: number | undefined): string { if (total === undefined || total <= UI_TRUNCATION_MAX) return ""; - return `
Showing last ${UI_TRUNCATION_MAX} of ${total} ${key}
`; + return `
Showing last ${UI_TRUNCATION_MAX} of ${total} ${escapeHtml(key)}
`; } function truncatedNoticeText(key: string, total: number | undefined): string { @@ -1075,14 +1075,16 @@ document.addEventListener("DOMContentLoaded", async () => { function createTranscriptEntryHTML(entry: TranscriptEntry): string { const timeStr = escapeHtml(entry.timestampLabel || formatDuration(entry.timestamp || 0)); const speaker = escapeHtml(entry.speaker || "Unknown"); - const initials = (entry.speaker || "Unknown") + const initials = speaker .split(" ") .filter(Boolean) .map((w) => w[0]) .join("") .toUpperCase() .slice(0, 2); - const isAudio = (entry.speaker || "") === "Audio"; + // speaker is already escapeHtml'd above, and "Audio" is pure ASCII + // so the comparison is safe (escapeHtml is a no-op for plain ASCII). + const isAudio = speaker === "Audio"; const text = escapeHtml(entry.text || ""); const chunkId = entry.id ? `transcript-${escapeHtml(entry.id)}` : ""; @@ -1095,9 +1097,9 @@ document.addEventListener("DOMContentLoaded", async () => {
${text}