mirror of https://github.com/openclaw/openclaw.git
test: dedupe bluebubbles local media send cases
This commit is contained in:
parent
168394980f
commit
8896a477df
|
|
@ -70,6 +70,70 @@ async function makeTempDir(): Promise<string> {
|
|||
return dir;
|
||||
}
|
||||
|
||||
async function makeTempFile(
|
||||
fileName: string,
|
||||
contents: string,
|
||||
dir?: string,
|
||||
): Promise<{ dir: string; filePath: string }> {
|
||||
const resolvedDir = dir ?? (await makeTempDir());
|
||||
const filePath = path.join(resolvedDir, fileName);
|
||||
await fs.writeFile(filePath, contents, "utf8");
|
||||
return { dir: resolvedDir, filePath };
|
||||
}
|
||||
|
||||
async function sendLocalMedia(params: {
|
||||
cfg: OpenClawConfig;
|
||||
mediaPath: string;
|
||||
accountId?: string;
|
||||
}) {
|
||||
return sendBlueBubblesMedia({
|
||||
cfg: params.cfg,
|
||||
to: "chat:123",
|
||||
accountId: params.accountId,
|
||||
mediaPath: params.mediaPath,
|
||||
});
|
||||
}
|
||||
|
||||
async function expectRejectedLocalMedia(params: {
|
||||
cfg: OpenClawConfig;
|
||||
mediaPath: string;
|
||||
error: RegExp;
|
||||
accountId?: string;
|
||||
}) {
|
||||
await expect(
|
||||
sendLocalMedia({
|
||||
cfg: params.cfg,
|
||||
mediaPath: params.mediaPath,
|
||||
accountId: params.accountId,
|
||||
}),
|
||||
).rejects.toThrow(params.error);
|
||||
|
||||
expect(sendBlueBubblesAttachmentMock).not.toHaveBeenCalled();
|
||||
}
|
||||
|
||||
async function expectAllowedLocalMedia(params: {
|
||||
cfg: OpenClawConfig;
|
||||
mediaPath: string;
|
||||
expectedAttachment: Record<string, unknown>;
|
||||
accountId?: string;
|
||||
expectMimeDetection?: boolean;
|
||||
}) {
|
||||
const result = await sendLocalMedia({
|
||||
cfg: params.cfg,
|
||||
mediaPath: params.mediaPath,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ messageId: "msg-1" });
|
||||
expect(sendBlueBubblesAttachmentMock).toHaveBeenCalledTimes(1);
|
||||
expect(sendBlueBubblesAttachmentMock.mock.calls[0]?.[0]).toEqual(
|
||||
expect.objectContaining(params.expectedAttachment),
|
||||
);
|
||||
if (params.expectMimeDetection) {
|
||||
expect(runtimeMocks.detectMime).toHaveBeenCalled();
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
const runtime = createMockRuntime();
|
||||
runtimeMocks = runtime.mocks;
|
||||
|
|
@ -110,57 +174,43 @@ describe("sendBlueBubblesMedia local-path hardening", () => {
|
|||
const outsideFile = path.join(outsideDir, "outside.txt");
|
||||
await fs.writeFile(outsideFile, "not allowed", "utf8");
|
||||
|
||||
await expect(
|
||||
sendBlueBubblesMedia({
|
||||
cfg: createConfig({ mediaLocalRoots: [allowedRoot] }),
|
||||
to: "chat:123",
|
||||
mediaPath: outsideFile,
|
||||
}),
|
||||
).rejects.toThrow(/not under any configured mediaLocalRoots/i);
|
||||
|
||||
expect(sendBlueBubblesAttachmentMock).not.toHaveBeenCalled();
|
||||
await expectRejectedLocalMedia({
|
||||
cfg: createConfig({ mediaLocalRoots: [allowedRoot] }),
|
||||
mediaPath: outsideFile,
|
||||
error: /not under any configured mediaLocalRoots/i,
|
||||
});
|
||||
});
|
||||
|
||||
it("allows local paths that are explicitly configured", async () => {
|
||||
const allowedRoot = await makeTempDir();
|
||||
const allowedFile = path.join(allowedRoot, "allowed.txt");
|
||||
await fs.writeFile(allowedFile, "allowed", "utf8");
|
||||
const { dir: allowedRoot, filePath: allowedFile } = await makeTempFile(
|
||||
"allowed.txt",
|
||||
"allowed",
|
||||
);
|
||||
|
||||
const result = await sendBlueBubblesMedia({
|
||||
await expectAllowedLocalMedia({
|
||||
cfg: createConfig({ mediaLocalRoots: [allowedRoot] }),
|
||||
to: "chat:123",
|
||||
mediaPath: allowedFile,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ messageId: "msg-1" });
|
||||
expect(sendBlueBubblesAttachmentMock).toHaveBeenCalledTimes(1);
|
||||
expect(sendBlueBubblesAttachmentMock.mock.calls[0]?.[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
expectedAttachment: {
|
||||
filename: "allowed.txt",
|
||||
contentType: "text/plain",
|
||||
}),
|
||||
);
|
||||
expect(runtimeMocks.detectMime).toHaveBeenCalled();
|
||||
},
|
||||
expectMimeDetection: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("allows file:// media paths and file:// local roots", async () => {
|
||||
const allowedRoot = await makeTempDir();
|
||||
const allowedFile = path.join(allowedRoot, "allowed.txt");
|
||||
await fs.writeFile(allowedFile, "allowed", "utf8");
|
||||
|
||||
const result = await sendBlueBubblesMedia({
|
||||
cfg: createConfig({ mediaLocalRoots: [pathToFileURL(allowedRoot).toString()] }),
|
||||
to: "chat:123",
|
||||
mediaPath: pathToFileURL(allowedFile).toString(),
|
||||
});
|
||||
|
||||
expect(result).toEqual({ messageId: "msg-1" });
|
||||
expect(sendBlueBubblesAttachmentMock).toHaveBeenCalledTimes(1);
|
||||
expect(sendBlueBubblesAttachmentMock.mock.calls[0]?.[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
filename: "allowed.txt",
|
||||
}),
|
||||
const { dir: allowedRoot, filePath: allowedFile } = await makeTempFile(
|
||||
"allowed.txt",
|
||||
"allowed",
|
||||
);
|
||||
|
||||
await expectAllowedLocalMedia({
|
||||
cfg: createConfig({ mediaLocalRoots: [pathToFileURL(allowedRoot).toString()] }),
|
||||
mediaPath: pathToFileURL(allowedFile).toString(),
|
||||
expectedAttachment: {
|
||||
filename: "allowed.txt",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("uses account-specific mediaLocalRoots over top-level roots", async () => {
|
||||
|
|
@ -213,15 +263,11 @@ describe("sendBlueBubblesMedia local-path hardening", () => {
|
|||
return;
|
||||
}
|
||||
|
||||
await expect(
|
||||
sendBlueBubblesMedia({
|
||||
cfg: createConfig({ mediaLocalRoots: [allowedRoot] }),
|
||||
to: "chat:123",
|
||||
mediaPath: linkPath,
|
||||
}),
|
||||
).rejects.toThrow(/not under any configured mediaLocalRoots/i);
|
||||
|
||||
expect(sendBlueBubblesAttachmentMock).not.toHaveBeenCalled();
|
||||
await expectRejectedLocalMedia({
|
||||
cfg: createConfig({ mediaLocalRoots: [allowedRoot] }),
|
||||
mediaPath: linkPath,
|
||||
error: /not under any configured mediaLocalRoots/i,
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects relative mediaLocalRoots entries", async () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue