Skip to content

Commit 0ff29e7

Browse files
Copilotmikebarkmin
andcommitted
Address code review: Add type safety and XSS protection
- Import and use Resource type instead of 'any' - Add DOMPurify to sanitize markdown HTML output - Remove unnecessary type assertion - Improve type safety across resource handling Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com>
1 parent 453c75b commit 0ff29e7

4 files changed

Lines changed: 31 additions & 6 deletions

File tree

packages/learningmap/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
},
3535
"dependencies": {
3636
"@szhsin/react-menu": "^4.5.0",
37+
"@types/dompurify": "^3.2.0",
3738
"@xyflow/react": "^12.8.6",
39+
"dompurify": "^3.3.0",
3840
"elkjs": "^0.11.0",
3941
"fast-deep-equal": "^3.1.3",
4042
"html-to-image": "1.11.13",

packages/learningmap/src/Drawer.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { Node } from "@xyflow/react";
2-
import { NodeData } from "./types";
2+
import { NodeData, Resource } from "./types";
33
import { X, Lock, CheckCircle } from "lucide-react";
44
import { Video } from "./Video";
55
import StarCircle from "./icons/StarCircle";
66
import { getTranslations } from "./translations";
77
import { marked } from "marked";
88
import { useMemo } from "react";
9+
import DOMPurify from "dompurify";
910

1011
interface DrawerProps {
1112
open: boolean;
@@ -59,10 +60,11 @@ function getCompletionOptional(node: Node<NodeData>, nodes: Node<NodeData>[]): N
5960
export function Drawer({ open, onClose, onUpdate, node, nodes, onNodeClick, language = "en" }: DrawerProps) {
6061
const t = getTranslations(language);
6162

62-
// Parse markdown description
63+
// Parse markdown description and sanitize HTML
6364
const descriptionHtml = useMemo(() => {
6465
if (!node.data?.description) return '';
65-
return marked.parse(node.data.description, { async: false }) as string;
66+
const rawHtml = marked.parse(node.data.description, { async: false });
67+
return DOMPurify.sanitize(rawHtml);
6668
}, [node.data?.description]);
6769

6870
if (!open) return null;
@@ -111,7 +113,7 @@ export function Drawer({ open, onClose, onUpdate, node, nodes, onNodeClick, lang
111113
<div className="drawer-resources" style={{ marginBottom: 16 }}>
112114
<div style={{ fontWeight: 600, marginBottom: 8 }}>{t.resourcesLabel}</div>
113115
<ul>
114-
{node.data?.resources.map((r: any, idx: number) => {
116+
{node.data?.resources.map((r: Resource, idx: number) => {
115117
if (r.type === "book") {
116118
return (
117119
<li key={idx}>

packages/learningmap/src/EditorDrawerTaskContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Node } from "@xyflow/react";
22
import { Plus, Trash2 } from "lucide-react";
3-
import { NodeData } from "./types";
3+
import { NodeData, Resource } from "./types";
44
import { getTranslations } from "./translations";
55

66
interface Props {
@@ -131,7 +131,7 @@ export function EditorDrawerTaskContent({
131131
</div>
132132
<div className="form-group">
133133
<label>{t.resources}</label>
134-
{(localNode.data.resources || []).map((resource: any, idx: number) => {
134+
{(localNode.data.resources || []).map((resource: Resource, idx: number) => {
135135
const isBook = resource.type === "book";
136136
return (
137137
<div key={idx} style={{ marginBottom: "16px", padding: "12px", border: "1px solid #e5e7eb", borderRadius: "6px" }}>

pnpm-lock.yaml

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)