diff --git a/crates/ai-formatting/src/rule_based.rs b/crates/ai-formatting/src/rule_based.rs index 2c804e4..ce41717 100644 --- a/crates/ai-formatting/src/rule_based.rs +++ b/crates/ai-formatting/src/rule_based.rs @@ -113,7 +113,10 @@ pub fn to_british_english(text: &str) -> String { if let Ok(re) = regex_lite::Regex::new(&pattern) { result = re .replace_all(&result, |caps: ®ex_lite::Captures| { - let matched = caps.get(0).unwrap().as_str(); + let Some(m) = caps.get(0) else { + return String::new(); + }; + let matched = m.as_str(); let us_base = us.replace("\\b", ""); let base_len = us_base.len(); let suffix = if matched.len() > base_len { @@ -121,12 +124,17 @@ pub fn to_british_english(text: &str) -> String { } else { "" }; - let first_char = matched.chars().next().unwrap(); + let Some(first_char) = matched.chars().next() else { + return String::new(); + }; let uk_clean = uk.replace("\\b", ""); if first_char.is_uppercase() { let mut chars = uk_clean.chars(); + let Some(first_uk) = chars.next() else { + return String::new(); + }; let upper_first: String = - chars.next().unwrap().to_uppercase().collect(); + first_uk.to_uppercase().collect(); format!( "{}{}{}", upper_first, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 6ab4dea..0d4d78c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -34,15 +34,17 @@ pub fn run() { } // Close-to-tray: hide window instead of exiting - let main_window = app.get_webview_window("main").unwrap(); - let win = main_window.clone(); - main_window.on_window_event(move |event| { - if let tauri::WindowEvent::CloseRequested { api, .. } = event - { - api.prevent_close(); - let _ = win.hide(); - } - }); + if let Some(main_window) = app.get_webview_window("main") { + let win = main_window.clone(); + main_window.on_window_event(move |event| { + if let tauri::WindowEvent::CloseRequested { api, .. } = + event + { + api.prevent_close(); + let _ = win.hide(); + } + }); + } Ok(()) }) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 66b97de..fff89c3 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -23,7 +23,7 @@ } ], "security": { - "csp": null + "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' asset: https://asset.localhost; connect-src ipc: http://ipc.localhost asset: https://asset.localhost http://localhost:* ws://localhost:*; media-src 'self' asset: https://asset.localhost" } }, "bundle": { diff --git a/src/lib/pages/DictationPage.svelte b/src/lib/pages/DictationPage.svelte index 5d46b34..f9249f6 100644 --- a/src/lib/pages/DictationPage.svelte +++ b/src/lib/pages/DictationPage.svelte @@ -47,9 +47,15 @@ onMount(async () => { unlisten = await listen("transcription-result", (event) => { - const result = typeof event.payload === "string" - ? JSON.parse(event.payload) - : event.payload; + let result; + try { + result = typeof event.payload === "string" + ? JSON.parse(event.payload) + : event.payload; + } catch (e) { + console.error("Failed to parse transcription result:", e); + return; + } handleResult(result); }); diff --git a/src/lib/pages/HistoryPage.svelte b/src/lib/pages/HistoryPage.svelte index 8618007..35c0b68 100644 --- a/src/lib/pages/HistoryPage.svelte +++ b/src/lib/pages/HistoryPage.svelte @@ -129,11 +129,11 @@ async function openViewer(item) { // Store item data for the viewer window try { - localStorage.setItem("ramble_viewer_item", JSON.stringify(item)); + localStorage.setItem("kon_viewer_item", JSON.stringify(item)); await invoke("open_viewer_window"); } catch { // Fallback: open in browser tab (dev mode) - localStorage.setItem("ramble_viewer_item", JSON.stringify(item)); + localStorage.setItem("kon_viewer_item", JSON.stringify(item)); window.open("/viewer", "_blank", "width=600,height=700"); } } diff --git a/src/lib/stores/page.svelte.js b/src/lib/stores/page.svelte.js index 0836f1f..5672329 100644 --- a/src/lib/stores/page.svelte.js +++ b/src/lib/stores/page.svelte.js @@ -12,7 +12,7 @@ export const page = $state({ // ---- Settings (persisted to localStorage) ---- -const SETTINGS_KEY = "ramble_settings"; +const SETTINGS_KEY = "kon_settings"; const defaults = { engine: "whisper", @@ -53,7 +53,7 @@ export function saveSettings() { // ---- Profiles (persisted to localStorage) ---- -const PROFILES_KEY = "ramble_profiles"; +const PROFILES_KEY = "kon_profiles"; function loadProfiles() { try { @@ -73,7 +73,7 @@ export function saveProfiles() { // ---- History (persisted to localStorage) ---- -const HISTORY_KEY = "ramble_history"; +const HISTORY_KEY = "kon_history"; function loadHistory() { try { @@ -104,7 +104,7 @@ export function deleteFromHistory(index) { // ---- Tasks (persisted to localStorage) ---- -const TASKS_KEY = "ramble_tasks"; +const TASKS_KEY = "kon_tasks"; function loadTasks() { try { @@ -169,7 +169,7 @@ export function uncompleteTask(id) { // ---- BroadcastChannel for multi-window task sync ---- const taskChannel = typeof BroadcastChannel !== "undefined" - ? new BroadcastChannel("ramble_tasks") + ? new BroadcastChannel("kon_tasks") : null; if (taskChannel) { @@ -189,7 +189,7 @@ function broadcastTasks() { // ---- Task Lists (persisted to localStorage) ---- -const TASK_LISTS_KEY = "ramble_task_lists"; +const TASK_LISTS_KEY = "kon_task_lists"; function loadTaskLists() { try { @@ -309,7 +309,7 @@ export function sortTaskLists(mode) { // BroadcastChannel for task lists const taskListChannel = typeof BroadcastChannel !== "undefined" - ? new BroadcastChannel("ramble_task_lists") + ? new BroadcastChannel("kon_task_lists") : null; if (taskListChannel) { @@ -329,7 +329,7 @@ function broadcastTaskLists() { // ---- Templates (persisted to localStorage) ---- -const TEMPLATES_KEY = "ramble_templates"; +const TEMPLATES_KEY = "kon_templates"; function loadTemplates() { try { diff --git a/src/routes/float/+layout@.svelte b/src/routes/float/+layout@.svelte index f8f8f03..e30a3e6 100644 --- a/src/routes/float/+layout@.svelte +++ b/src/routes/float/+layout@.svelte @@ -32,7 +32,7 @@ // Listen for settings changes 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 {} diff --git a/src/routes/viewer/+layout@.svelte b/src/routes/viewer/+layout@.svelte index 4db452b..460d9d8 100644 --- a/src/routes/viewer/+layout@.svelte +++ b/src/routes/viewer/+layout@.svelte @@ -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 {} } }); diff --git a/src/routes/viewer/+page.svelte b/src/routes/viewer/+page.svelte index b3d59c3..9efe90f 100644 --- a/src/routes/viewer/+page.svelte +++ b/src/routes/viewer/+page.svelte @@ -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, """); const q = searchQuery.trim(); const regex = new RegExp(`(${q.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`, "gi"); - return text.replace(regex, '$1'); + return escaped.replace(regex, '$1'); } // 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 {} }