mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-19 13:12:48 +03:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3e0f4c6da |
@@ -218,6 +218,50 @@ test.describe("Chat — streaming @medium", () => {
|
|||||||
frigateApp.page.getByText(/searching for people/i),
|
frigateApp.page.getByText(/searching for people/i),
|
||||||
).toBeVisible({ timeout: 5_000 });
|
).toBeVisible({ timeout: 5_000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("assistant markdown renders only same-origin images", async ({
|
||||||
|
frigateApp,
|
||||||
|
}) => {
|
||||||
|
const reply =
|
||||||
|
" " +
|
||||||
|
" " +
|
||||||
|
"[offsite](https://evil.example/page)";
|
||||||
|
await installChatStreamOverride(frigateApp, [
|
||||||
|
{ type: "content", delta: reply },
|
||||||
|
{
|
||||||
|
type: "messages",
|
||||||
|
messages: [
|
||||||
|
{ role: "system", content: "sys" },
|
||||||
|
{ role: "user", content: "show me" },
|
||||||
|
{ role: "assistant", content: reply },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ type: "done" },
|
||||||
|
]);
|
||||||
|
const offsiteRequests: string[] = [];
|
||||||
|
frigateApp.page.on("request", (req) => {
|
||||||
|
if (req.url().includes("evil.example")) offsiteRequests.push(req.url());
|
||||||
|
});
|
||||||
|
await frigateApp.goto("/chat");
|
||||||
|
const input = frigateApp.page.getByPlaceholder(/ask/i);
|
||||||
|
await expect(input).toBeVisible({ timeout: 10_000 });
|
||||||
|
await input.fill("show me");
|
||||||
|
await input.press("Enter");
|
||||||
|
|
||||||
|
await expect(frigateApp.page.getByText("leaked alt")).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
});
|
||||||
|
await expect(
|
||||||
|
frigateApp.page.locator('img[src*="evil.example"]'),
|
||||||
|
).toHaveCount(0);
|
||||||
|
await expect(
|
||||||
|
frigateApp.page.locator('img[src="/api/events/abc/thumbnail.webp"]'),
|
||||||
|
).toHaveCount(1);
|
||||||
|
const link = frigateApp.page.getByRole("link", { name: "offsite" });
|
||||||
|
await expect(link).toHaveAttribute("target", "_blank");
|
||||||
|
await expect(link).toHaveAttribute("rel", "noopener noreferrer");
|
||||||
|
expect(offsiteRequests).toEqual([]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe("Chat — stop @medium", () => {
|
test.describe("Chat — stop @medium", () => {
|
||||||
|
|||||||
@@ -18,6 +18,18 @@ import { cn } from "@/lib/utils";
|
|||||||
import { ChatAttachmentChip } from "@/components/chat/ChatAttachmentChip";
|
import { ChatAttachmentChip } from "@/components/chat/ChatAttachmentChip";
|
||||||
import { parseAttachedEvent } from "@/utils/chatUtil";
|
import { parseAttachedEvent } from "@/utils/chatUtil";
|
||||||
import type { ChatStats, ShowStatsMode } from "@/types/chat";
|
import type { ChatStats, ShowStatsMode } from "@/types/chat";
|
||||||
|
import { baseUrl } from "@/api/baseUrl";
|
||||||
|
|
||||||
|
// Assistant output can carry prompt-injected URLs, and the browser fetches
|
||||||
|
// images without a click, so only same-origin images render.
|
||||||
|
function isSameOrigin(url: string | undefined): boolean {
|
||||||
|
if (!url) return false;
|
||||||
|
try {
|
||||||
|
return new URL(url, baseUrl).origin === window.location.origin;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type MessageBubbleProps = {
|
type MessageBubbleProps = {
|
||||||
role: "user" | "assistant";
|
role: "user" | "assistant";
|
||||||
@@ -223,6 +235,23 @@ export function MessageBubble({
|
|||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
img: ({ node: _n, src, alt, ...props }) =>
|
||||||
|
typeof src === "string" && isSameOrigin(src) ? (
|
||||||
|
<img src={src} alt={alt} {...props} />
|
||||||
|
) : (
|
||||||
|
<>{alt}</>
|
||||||
|
),
|
||||||
|
a: ({ node: _n, href, ...props }) =>
|
||||||
|
isSameOrigin(href) ? (
|
||||||
|
<a href={href} {...props} />
|
||||||
|
) : (
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
|
|||||||
Reference in New Issue
Block a user