summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-05-20 13:31:58 +0900
committerAdam Malczewski <[email protected]>2026-05-20 13:31:58 +0900
commit6ec5803e953534c077f863d723972c78796fe16a (patch)
treeed49ea0853d62497dfa0c580f466fa2ae3cf5b0c
parent19144599bcb6d6a180d4a2cfe1bdc7f58780ac0c (diff)
downloaddispatch-6ec5803e953534c077f863d723972c78796fe16a.tar.gz
dispatch-6ec5803e953534c077f863d723972c78796fe16a.zip
fix: gemini review — XSS sanitization, collapse-arrow padding, redundant alias
-rw-r--r--bun.lock6
-rw-r--r--packages/frontend/package.json2
-rw-r--r--packages/frontend/src/lib/components/ChatMessage.svelte2
-rw-r--r--packages/frontend/src/lib/components/MarkdownRenderer.svelte6
4 files changed, 12 insertions, 4 deletions
diff --git a/bun.lock b/bun.lock
index 44cf8c2..a728a8b 100644
--- a/bun.lock
+++ b/bun.lock
@@ -39,6 +39,7 @@
"name": "@dispatch/frontend",
"version": "0.0.1",
"dependencies": {
+ "dompurify": "^3.4.5",
"highlight.js": "^11.11.1",
"marked": "^18.0.4",
"marked-highlight": "^2.2.4",
@@ -47,6 +48,7 @@
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/vite": "^4.0.0",
+ "@types/dompurify": "^3.2.0",
"daisyui": "^5.0.0",
"svelte-check": "^4.0.0",
"tailwindcss": "^4.0.0",
@@ -247,6 +249,8 @@
"@types/diff-match-patch": ["@types/[email protected]", "", {}, "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg=="],
+ "@types/dompurify": ["@types/[email protected]", "", { "dependencies": { "dompurify": "*" } }, "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg=="],
+
"@types/estree": ["@types/[email protected]", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ=="],
@@ -307,6 +311,8 @@
"diff-match-patch": ["[email protected]", "", {}, "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="],
+ "dompurify": ["[email protected]", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA=="],
+
"enhanced-resolve": ["[email protected]", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-wE4fDO8OjJhrPFH69HUQStq5oKvGRTNXEyW+k5C/pUQLASSsTu7obd2V3GvCDgPcY9AWjhJ4jz9Kh7iRvrxhJg=="],
"es-module-lexer": ["[email protected]", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index 2b68692..37b794d 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -12,6 +12,7 @@
"typecheck": "svelte-check --tsconfig ./tsconfig.json"
},
"dependencies": {
+ "dompurify": "^3.4.5",
"highlight.js": "^11.11.1",
"marked": "^18.0.4",
"marked-highlight": "^2.2.4",
@@ -20,6 +21,7 @@
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/vite": "^4.0.0",
+ "@types/dompurify": "^3.2.0",
"daisyui": "^5.0.0",
"svelte-check": "^4.0.0",
"tailwindcss": "^4.0.0",
diff --git a/packages/frontend/src/lib/components/ChatMessage.svelte b/packages/frontend/src/lib/components/ChatMessage.svelte
index 1b92de3..09182f3 100644
--- a/packages/frontend/src/lib/components/ChatMessage.svelte
+++ b/packages/frontend/src/lib/components/ChatMessage.svelte
@@ -13,7 +13,7 @@ const isUser = $derived(message.role === "user");
{#if message.thinking}
<div class="collapse collapse-arrow mb-2">
<input type="checkbox" />
- <div class="collapse-title text-sm opacity-60 italic p-0 min-h-0">Thinking...</div>
+ <div class="collapse-title text-sm opacity-60 italic py-0 pl-0 pr-8 min-h-0">Thinking...</div>
<div class="collapse-content text-sm opacity-60 italic p-0">
<p class="whitespace-pre-wrap mt-1">{message.thinking}</p>
</div>
diff --git a/packages/frontend/src/lib/components/MarkdownRenderer.svelte b/packages/frontend/src/lib/components/MarkdownRenderer.svelte
index 88dd42a..f9925c6 100644
--- a/packages/frontend/src/lib/components/MarkdownRenderer.svelte
+++ b/packages/frontend/src/lib/components/MarkdownRenderer.svelte
@@ -1,6 +1,7 @@
<script lang="ts">
import { Marked } from "marked";
import { markedHighlight } from "marked-highlight";
+ import DOMPurify from "dompurify";
import hljs from "highlight.js/lib/core";
// Hot set — matches roughly what ChatGPT preloads. Registered eagerly so
// common code blocks highlight on first paint without a network roundtrip.
@@ -71,7 +72,6 @@
svg: "xml",
md: "markdown",
mdx: "markdown",
- dockerfile: "dockerfile",
golang: "go",
rs: "rust",
kt: "kotlin",
@@ -159,8 +159,8 @@
const myToken = ++renderToken;
(async () => {
try {
- const result = (await md.parse(src)) as string;
- if (myToken === renderToken) html = result;
+ const raw = (await md.parse(src)) as string;
+ if (myToken === renderToken) html = DOMPurify.sanitize(raw);
} catch {
// swallow — keeps last successful render visible
}