mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-09 15:35:17 +00:00
fix(discord): keep attachment metadata when media fetch is blocked
Preserve inbound attachment/sticker metadata in Discord message context when media download fails (for example due to SSRF blocking), so agents still see file references instead of silent drops. Closes #28816
This commit is contained in:
committed by
Peter Steinberger
parent
e4e5d9c98c
commit
0a67033fe3
@@ -139,6 +139,34 @@ describe("resolveForwardedMediaList", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps forwarded attachment metadata when download fails", async () => {
|
||||
const attachment = {
|
||||
id: "att-fallback",
|
||||
url: "https://cdn.discordapp.com/attachments/1/fallback.png",
|
||||
filename: "fallback.png",
|
||||
content_type: "image/png",
|
||||
};
|
||||
fetchRemoteMedia.mockRejectedValueOnce(new Error("blocked by ssrf guard"));
|
||||
|
||||
const result = await resolveForwardedMediaList(
|
||||
asMessage({
|
||||
rawData: {
|
||||
message_snapshots: [{ message: { attachments: [attachment] } }],
|
||||
},
|
||||
}),
|
||||
512,
|
||||
);
|
||||
|
||||
expect(saveMediaBuffer).not.toHaveBeenCalled();
|
||||
expect(result).toEqual([
|
||||
{
|
||||
path: attachment.url,
|
||||
contentType: "image/png",
|
||||
placeholder: "<media:image>",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("downloads forwarded stickers", async () => {
|
||||
const sticker = {
|
||||
id: "sticker-1",
|
||||
@@ -279,6 +307,57 @@ describe("resolveMediaList", () => {
|
||||
expect.objectContaining({ fetchImpl: proxyFetch }),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps attachment metadata when download fails", async () => {
|
||||
const attachment = {
|
||||
id: "att-main-fallback",
|
||||
url: "https://cdn.discordapp.com/attachments/1/main-fallback.png",
|
||||
filename: "main-fallback.png",
|
||||
content_type: "image/png",
|
||||
};
|
||||
fetchRemoteMedia.mockRejectedValueOnce(new Error("blocked by ssrf guard"));
|
||||
|
||||
const result = await resolveMediaList(
|
||||
asMessage({
|
||||
attachments: [attachment],
|
||||
}),
|
||||
512,
|
||||
);
|
||||
|
||||
expect(saveMediaBuffer).not.toHaveBeenCalled();
|
||||
expect(result).toEqual([
|
||||
{
|
||||
path: attachment.url,
|
||||
contentType: "image/png",
|
||||
placeholder: "<media:image>",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps sticker metadata when sticker download fails", async () => {
|
||||
const sticker = {
|
||||
id: "sticker-fallback",
|
||||
name: "fallback",
|
||||
format_type: StickerFormatType.PNG,
|
||||
};
|
||||
fetchRemoteMedia.mockRejectedValueOnce(new Error("blocked by ssrf guard"));
|
||||
|
||||
const result = await resolveMediaList(
|
||||
asMessage({
|
||||
stickers: [sticker],
|
||||
}),
|
||||
512,
|
||||
);
|
||||
|
||||
expect(saveMediaBuffer).not.toHaveBeenCalled();
|
||||
expect(result).toEqual([
|
||||
{
|
||||
path: "https://media.discordapp.net/stickers/sticker-fallback.png",
|
||||
contentType: "image/png",
|
||||
placeholder: "<media:sticker>",
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Discord media SSRF policy", () => {
|
||||
|
||||
@@ -250,6 +250,12 @@ async function appendResolvedMediaFromAttachments(params: {
|
||||
} catch (err) {
|
||||
const id = attachment.id ?? attachment.url;
|
||||
logVerbose(`${params.errorPrefix} ${id}: ${String(err)}`);
|
||||
// Preserve attachment context even when remote fetch is blocked/fails.
|
||||
params.out.push({
|
||||
path: attachment.url,
|
||||
contentType: attachment.content_type,
|
||||
placeholder: inferPlaceholder(attachment),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,6 +312,19 @@ function formatStickerError(err: unknown): string {
|
||||
}
|
||||
}
|
||||
|
||||
function inferStickerContentType(sticker: APIStickerItem): string | undefined {
|
||||
switch (sticker.format_type) {
|
||||
case StickerFormatType.GIF:
|
||||
return "image/gif";
|
||||
case StickerFormatType.APNG:
|
||||
case StickerFormatType.Lottie:
|
||||
case StickerFormatType.PNG:
|
||||
return "image/png";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function appendResolvedMediaFromStickers(params: {
|
||||
stickers?: APIStickerItem[] | null;
|
||||
maxBytes: number;
|
||||
@@ -348,6 +367,14 @@ async function appendResolvedMediaFromStickers(params: {
|
||||
}
|
||||
if (lastError) {
|
||||
logVerbose(`${params.errorPrefix} ${sticker.id}: ${formatStickerError(lastError)}`);
|
||||
const fallback = candidates[0];
|
||||
if (fallback) {
|
||||
params.out.push({
|
||||
path: fallback.url,
|
||||
contentType: inferStickerContentType(sticker),
|
||||
placeholder: "<media:sticker>",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user