🐛 fix(chatMessage): sanitize HTML content to prevent potential XSS attacks

 feat(chatMessage): improve rendering of multi-line messages
The `convert` variable is now imported before being used to convert ANSI to HTML. Additionally, the `DOMPurify` library is imported and used to sanitize the HTML content before rendering it, preventing potential XSS attacks. The rendering of multi-line messages has been improved by splitting the message by newline characters and rendering each line separately with a line break.
This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-06-29 10:02:28 -03:00
commit 3faf5f5b96
2 changed files with 14 additions and 14 deletions

View file

@ -2,9 +2,9 @@ import { useState } from "react";
import { ChatMessageType } from "../../../types/chat";
import { nodeColors } from "../../../utils";
import Convert from "ansi-to-html";
const convert = new Convert({ newline: true });
import { MessageCircle } from "lucide-react";
import DOMPurify from "dompurify";
const convert = new Convert({ newline: true });
export default function ChatMessage({ chat }: { chat: ChatMessageType }) {
const [hidden, setHidden] = useState(true);
return (
@ -23,13 +23,14 @@ export default function ChatMessage({ chat }: { chat: ChatMessageType }) {
<MessageCircle className="w-5 h-5 animate-bounce" />
</div>
)}
{chat.thought && chat.thought !== "" && !hidden && (
<div
onClick={() => setHidden((prev) => !prev)}
style={{ backgroundColor: nodeColors["thought"] }}
className=" text-start inline-block w-full pb-3 pt-3 px-5 cursor-pointer"
className="text-start inline-block w-full pb-3 pt-3 px-5 cursor-pointer"
dangerouslySetInnerHTML={{
__html: convert.toHtml(chat.thought),
__html: DOMPurify.sanitize(convert.toHtml(chat.thought)),
}}
></div>
)}

View file

@ -11,7 +11,7 @@ import remarkMath from "remark-math";
import { CodeBlock } from "./codeBlock";
import Convert from "ansi-to-html";
import { User2, MessageCircle } from "lucide-react";
import DOMPurify from "dompurify";
export default function ChatMessage({
chat,
lockChat,
@ -78,10 +78,9 @@ export default function ChatMessage({
{chat.thought && chat.thought !== "" && !hidden && (
<div
onClick={() => setHidden((prev) => !prev)}
className=" text-start inline-block rounded-md text-gray-600 dark:text-gray-200 h-full border border-gray-300 dark:border-gray-500
bg-muted dark:bg-gray-800 w-[95%] pb-3 pt-3 px-2 ml-3 cursor-pointer scrollbar-hide overflow-scroll"
className="text-start inline-block rounded-md text-gray-600 dark:text-gray-200 h-full border border-gray-300 dark:border-gray-500 bg-muted dark:bg-gray-800 w-[95%] pb-3 pt-3 px-2 ml-3 cursor-pointer scrollbar-hide overflow-scroll"
dangerouslySetInnerHTML={{
__html: convert.toHtml(chat.thought),
__html: DOMPurify.sanitize(convert.toHtml(chat.thought)),
}}
></div>
)}
@ -152,12 +151,12 @@ export default function ChatMessage({
) : (
<div className="w-full flex items-center">
<div className="text-start inline-block px-3 text-gray-600 dark:text-white">
<span
className="text-gray-600 dark:text-gray-200"
dangerouslySetInnerHTML={{
__html: message.replace(/\n/g, "<br>"),
}}
></span>
{message.split("\n").map((line, index) => (
<span key={index}>
{line}
<br />
</span>
))}
</div>
</div>
)}