From 910230cbf87597e1e5552b409be92bde504809a8 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:18:04 +0200 Subject: [PATCH] fix: add highlighting to search match context snippets The command palette renders matchContext via dangerouslySetInnerHTML expecting HTML with tags, but extractSnippet() returned plain text. Wrap the matched term in tags and escape surrounding text to prevent XSS. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../server/app/search/ClickHouseSearchIndex.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchIndex.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchIndex.java index f3df489d..a5a1f516 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchIndex.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchIndex.java @@ -289,7 +289,14 @@ public class ClickHouseSearchIndex implements SearchIndex { if (idx < 0) return null; int start = Math.max(0, idx - contextChars / 2); int end = Math.min(text.length(), idx + searchTerm.length() + contextChars / 2); - return (start > 0 ? "..." : "") + text.substring(start, end) + (end < text.length() ? "..." : ""); + String before = escapeHtml(text.substring(start, idx)); + String match = escapeHtml(text.substring(idx, idx + searchTerm.length())); + String after = escapeHtml(text.substring(idx + searchTerm.length(), end)); + return (start > 0 ? "..." : "") + before + "" + match + "" + after + (end < text.length() ? "..." : ""); + } + + private static String escapeHtml(String s) { + return s.replace("&", "&").replace("<", "<").replace(">", ">"); } private static String escapeLike(String term) {