mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-24 09:19:34 +00:00
143 lines
5.5 KiB
TypeScript
143 lines
5.5 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import { resolveStateDir } from "../config/paths.js";
|
|
import {
|
|
classifyMediaReferenceSource,
|
|
MediaReferenceError,
|
|
normalizeMediaReferenceSource,
|
|
resolveInboundMediaReference,
|
|
resolveMediaReferenceLocalPath,
|
|
} from "./media-reference.js";
|
|
|
|
describe("media reference helpers", () => {
|
|
it("normalizes outbound MEDIA tags without changing canonical media URIs", () => {
|
|
expect(normalizeMediaReferenceSource(" MEDIA: ./out.png")).toBe("./out.png");
|
|
expect(normalizeMediaReferenceSource("media://inbound/a.png")).toBe("media://inbound/a.png");
|
|
});
|
|
|
|
it("classifies supported and unsupported media reference schemes", () => {
|
|
expect(classifyMediaReferenceSource("media://inbound/a.png")).toMatchObject({
|
|
isMediaStoreUrl: true,
|
|
hasUnsupportedScheme: false,
|
|
});
|
|
expect(classifyMediaReferenceSource("data:image/png;base64,cG5n")).toMatchObject({
|
|
isDataUrl: true,
|
|
hasUnsupportedScheme: false,
|
|
});
|
|
expect(
|
|
classifyMediaReferenceSource("data:image/png;base64,cG5n", { allowDataUrl: false }),
|
|
).toMatchObject({
|
|
isDataUrl: true,
|
|
hasUnsupportedScheme: true,
|
|
});
|
|
expect(classifyMediaReferenceSource("ftp://example.test/a.png")).toMatchObject({
|
|
hasUnsupportedScheme: true,
|
|
});
|
|
expect(classifyMediaReferenceSource("C:\\Users\\pete\\image.png")).toMatchObject({
|
|
looksLikeWindowsDrivePath: true,
|
|
hasUnsupportedScheme: false,
|
|
});
|
|
});
|
|
|
|
it("resolves canonical inbound media URIs", async () => {
|
|
const stateDir = resolveStateDir();
|
|
const id = `ref-${Date.now()}-${Math.random().toString(36).slice(2)}.png`;
|
|
const filePath = path.join(stateDir, "media", "inbound", id);
|
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
await fs.writeFile(filePath, Buffer.from("png"));
|
|
|
|
try {
|
|
await expect(resolveInboundMediaReference(`media://inbound/${id}`)).resolves.toMatchObject({
|
|
id,
|
|
normalizedSource: `media://inbound/${id}`,
|
|
physicalPath: filePath,
|
|
sourceType: "uri",
|
|
});
|
|
} finally {
|
|
await fs.rm(filePath, { force: true });
|
|
}
|
|
});
|
|
|
|
it("maps canonical inbound media URIs to local paths for direct file readers", async () => {
|
|
const stateDir = resolveStateDir();
|
|
const id = `ref-local-path-${Date.now()}-${Math.random().toString(36).slice(2)}.png`;
|
|
const filePath = path.join(stateDir, "media", "inbound", id);
|
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
await fs.writeFile(filePath, Buffer.from("png"));
|
|
|
|
try {
|
|
await expect(resolveMediaReferenceLocalPath(`media://inbound/${id}`)).resolves.toBe(filePath);
|
|
await expect(resolveMediaReferenceLocalPath(" MEDIA: ./out.png")).resolves.toBe("./out.png");
|
|
} finally {
|
|
await fs.rm(filePath, { force: true });
|
|
}
|
|
});
|
|
|
|
it("resolves direct absolute paths only for first-level inbound media files", async () => {
|
|
const stateDir = resolveStateDir();
|
|
const id = `ref-path-${Date.now()}-${Math.random().toString(36).slice(2)}.png`;
|
|
const filePath = path.join(stateDir, "media", "inbound", id);
|
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
await fs.writeFile(filePath, Buffer.from("png"));
|
|
|
|
try {
|
|
await expect(resolveInboundMediaReference(filePath)).resolves.toMatchObject({
|
|
id,
|
|
physicalPath: filePath,
|
|
sourceType: "path",
|
|
});
|
|
await expect(
|
|
resolveInboundMediaReference(path.join(stateDir, "media", "inbound", "nested", id)),
|
|
).resolves.toBeNull();
|
|
await expect(
|
|
resolveInboundMediaReference(path.join(stateDir, "media", "outbound", id)),
|
|
).resolves.toBeNull();
|
|
} finally {
|
|
await fs.rm(filePath, { force: true });
|
|
}
|
|
});
|
|
|
|
it("rejects inbound media URIs with unsupported locations or unsafe ids", async () => {
|
|
await expect(resolveInboundMediaReference("media://outbound/a.png")).rejects.toMatchObject({
|
|
code: "path-not-allowed",
|
|
});
|
|
await expect(
|
|
resolveInboundMediaReference("media://inbound/nested%2Fa.png"),
|
|
).rejects.toBeInstanceOf(MediaReferenceError);
|
|
await expect(
|
|
resolveInboundMediaReference("media://inbound/nested%2Fa.png"),
|
|
).rejects.toMatchObject({ code: "invalid-path" });
|
|
await expect(resolveInboundMediaReference("media://inbound/")).rejects.toMatchObject({
|
|
code: "invalid-path",
|
|
});
|
|
await expect(resolveInboundMediaReference("media://inbound/%00.png")).rejects.toMatchObject({
|
|
code: "invalid-path",
|
|
});
|
|
});
|
|
|
|
it("rejects symlinked inbound media files", async () => {
|
|
const stateDir = resolveStateDir();
|
|
const targetDir = path.join(stateDir, "media-reference-test-target");
|
|
const targetPath = path.join(targetDir, "target.png");
|
|
const id = `ref-link-${Date.now()}-${Math.random().toString(36).slice(2)}.png`;
|
|
const linkPath = path.join(stateDir, "media", "inbound", id);
|
|
await fs.mkdir(targetDir, { recursive: true });
|
|
await fs.mkdir(path.dirname(linkPath), { recursive: true });
|
|
await fs.writeFile(targetPath, Buffer.from("png"));
|
|
await fs.symlink(targetPath, linkPath);
|
|
|
|
try {
|
|
await expect(resolveInboundMediaReference(`media://inbound/${id}`)).rejects.toMatchObject({
|
|
code: "invalid-path",
|
|
});
|
|
await expect(resolveInboundMediaReference(linkPath)).rejects.toMatchObject({
|
|
code: "invalid-path",
|
|
});
|
|
} finally {
|
|
await fs.rm(linkPath, { force: true });
|
|
await fs.rm(targetDir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|