


























@@ -47,6 +47,7 @@ const TEST_URL_FILE_DOWNLOAD = createTestUrl("dl");
4747const TEST_URL_OUTSIDE_ALLOWLIST = "https://evil.test/img";
4848const CONTENT_TYPE_IMAGE_PNG = "image/png";
4949const CONTENT_TYPE_APPLICATION_PDF = "application/pdf";
50+const CONTENT_TYPE_APPLICATION_ZIP = "application/zip";
5051const CONTENT_TYPE_TEXT_HTML = "text/html";
5152const CONTENT_TYPE_TEAMS_FILE_DOWNLOAD_INFO = "application/vnd.microsoft.teams.file.download.info";
5253const REDIRECT_STATUS_CODES = new Set([301, 302, 303, 307, 308]);
@@ -59,21 +60,21 @@ type RemoteMediaFetchParams = {
5960fetchImpl?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
6061};
616262-const detectMimeMock = vi.fn(async () => CONTENT_TYPE_IMAGE_PNG);
63-const saveMediaBufferMock = vi.fn(
64-async (
65- _buffer: Buffer,
66- contentType?: string,
67- _subdir?: string,
68- _maxBytes?: number,
69- _originalFilename?: string,
70-) => ({
71- id: "saved.png",
72- path: contentType === CONTENT_TYPE_APPLICATION_PDF ? SAVED_PDF_PATH : SAVED_PNG_PATH,
73- size: Buffer.byteLength(PNG_BUFFER),
74- contentType: contentType ?? CONTENT_TYPE_IMAGE_PNG,
75- }),
76-);
63+const detectMimeDefault = async () => CONTENT_TYPE_IMAGE_PNG;
64+const saveMediaBufferDefault = async (
65+_buffer: Buffer,
66+contentType?: string,
67+_subdir?: string,
68+_maxBytes?: number,
69+_originalFilename?: string,
70+) => ({
71+id: "saved.png",
72+path: contentType === CONTENT_TYPE_APPLICATION_PDF ? SAVED_PDF_PATH : SAVED_PNG_PATH,
73+size: Buffer.byteLength(PNG_BUFFER),
74+contentType: contentType ?? CONTENT_TYPE_IMAGE_PNG,
75+});
76+const detectMimeMock = vi.fn(detectMimeDefault);
77+const saveMediaBufferMock = vi.fn(saveMediaBufferDefault);
7778function isHostnameAllowedByPattern(hostname: string, pattern: string): boolean {
7879if (pattern.startsWith("*.")) {
7980const suffix = pattern.slice(2);
@@ -422,8 +423,10 @@ const runAttachmentAuthRetryCase = async ({
422423423424describe("msteams attachments", () => {
424425beforeEach(() => {
425-detectMimeMock.mockClear();
426-saveMediaBufferMock.mockClear();
426+detectMimeMock.mockReset();
427+detectMimeMock.mockImplementation(detectMimeDefault);
428+saveMediaBufferMock.mockReset();
429+saveMediaBufferMock.mockImplementation(saveMediaBufferDefault);
427430readRemoteMediaBufferMock.mockClear();
428431saveRemoteMediaMock.mockClear();
429432saveResponseMediaMock.mockClear();
@@ -447,6 +450,33 @@ describe("msteams attachments", () => {
447450expectMediaBufferSaved();
448451});
449452453+it("stores every inline data:image base64 payload", async () => {
454+const media = await downloadMSTeamsAttachments(
455+buildDownloadParams([
456+ ...createHtmlImageAttachments([
457+`data:image/png;base64,${PNG_BASE64}`,
458+`data:image/png;base64,${PNG_BASE64}`,
459+]),
460+]),
461+);
462+463+expectAttachmentMediaLength(media, 2);
464+expect(saveMediaBufferMock).toHaveBeenCalledTimes(2);
465+});
466+467+it("skips inline data:image payloads whose bytes sniff as non-image", async () => {
468+detectMimeMock.mockResolvedValueOnce(CONTENT_TYPE_APPLICATION_ZIP);
469+470+const media = await downloadMSTeamsAttachments(
471+buildDownloadParams([
472+ ...createHtmlImageAttachments([`data:image/png;base64,${PNG_BASE64}`]),
473+]),
474+);
475+476+expectAttachmentMediaLength(media, 0);
477+expect(saveMediaBufferMock).not.toHaveBeenCalled();
478+});
479+450480it.each<AttachmentAuthRetryCase>(ATTACHMENT_AUTH_RETRY_CASES)(
451481"$label",
452482runAttachmentAuthRetryCase,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。