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 {}
}