fix(kon): security audit fixes — CSP, XSS, unwraps, key rename
Security fixes from code audit:
- CSP re-enabled in tauri.conf.json with strict directives
(was null — critical vulnerability)
- XSS fix in viewer highlightText(): HTML entities escaped before
inserting <mark> tags via {@html}
- Removed 3 unwrap() calls in rule_based.rs British English conversion
— replaced with safe let-else guards
- Removed unwrap() on main window lookup in lib.rs setup — now uses
if-let for graceful handling
- Wrapped JSON.parse in DictationPage transcription-result listener
with try/catch
Rebrand cleanup:
- Renamed all localStorage keys from ramble_* to kon_* across
7 files (stores, viewer, float, history)
12 tests passing, clippy clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
// Sync settings from main window
|
||||
if (typeof window !== "undefined") {
|
||||
window.addEventListener("storage", (e) => {
|
||||
if (e.key === "ramble_settings" && e.newValue) {
|
||||
if (e.key === "kon_settings" && e.newValue) {
|
||||
try { Object.assign(settings, JSON.parse(e.newValue)); } catch {}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
// Load item data from localStorage (set by HistoryPage before opening this window)
|
||||
onMount(() => {
|
||||
try {
|
||||
const raw = localStorage.getItem("ramble_viewer_item");
|
||||
const raw = localStorage.getItem("kon_viewer_item");
|
||||
if (raw) {
|
||||
item = JSON.parse(raw);
|
||||
if (item.audioPath) {
|
||||
@@ -49,7 +49,7 @@
|
||||
});
|
||||
|
||||
function handleStorageChange(e) {
|
||||
if (e.key === "ramble_viewer_item" && e.newValue) {
|
||||
if (e.key === "kon_viewer_item" && e.newValue) {
|
||||
try {
|
||||
if (audioEl) { audioEl.pause(); }
|
||||
cancelAnimationFrame(animFrameId);
|
||||
@@ -150,12 +150,13 @@
|
||||
|
||||
let matchCount = $derived.by(() => matchingSegments.size);
|
||||
|
||||
// Highlight search matches in text
|
||||
// Highlight search matches in text (XSS-safe: escapes HTML entities first)
|
||||
function highlightText(text) {
|
||||
if (!searchQuery.trim()) return text;
|
||||
const escaped = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
||||
const q = searchQuery.trim();
|
||||
const regex = new RegExp(`(${q.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`, "gi");
|
||||
return text.replace(regex, '<mark class="bg-accent/25 text-text rounded px-0.5">$1</mark>');
|
||||
return escaped.replace(regex, '<mark class="bg-accent/25 text-text rounded px-0.5">$1</mark>');
|
||||
}
|
||||
|
||||
// Segment editing
|
||||
@@ -200,17 +201,17 @@
|
||||
function saveItemToHistory() {
|
||||
// Persist edits back to localStorage history
|
||||
try {
|
||||
const raw = localStorage.getItem("ramble_history");
|
||||
const raw = localStorage.getItem("kon_history");
|
||||
if (raw) {
|
||||
const hist = JSON.parse(raw);
|
||||
const idx = hist.findIndex((h) => h.id === item.id);
|
||||
if (idx >= 0) {
|
||||
hist[idx] = { ...hist[idx], segments: item.segments, text: item.text };
|
||||
localStorage.setItem("ramble_history", JSON.stringify(hist));
|
||||
localStorage.setItem("kon_history", JSON.stringify(hist));
|
||||
}
|
||||
}
|
||||
// Also update the viewer item cache
|
||||
localStorage.setItem("ramble_viewer_item", JSON.stringify(item));
|
||||
localStorage.setItem("kon_viewer_item", JSON.stringify(item));
|
||||
} catch {}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user