fix: download winmail.dat parts whose type a browser would drop instead of opening them

This commit is contained in:
Linus Rath
2026-10-26 11:22:10 +01:00
parent d76a472022
commit 3caa83f1a6
2 changed files with 17 additions and 2 deletions
+12 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from 'vitest';
import { getFilePreviewKind, imageBlobUrl, inertBlobType, isFilePreviewable, previewBlobType, toInertBlob } from '../file-preview';
import { getFilePreviewKind, imageBlobUrl, inertBlobType, isFilePreviewable, isMimeTypeSafeForInlinePreview, previewBlobType, toInertBlob } from '../file-preview';
describe('file preview detection', () => {
it('detects browser-renderable image attachments', () => {
@@ -47,6 +47,17 @@ describe('inert blob typing for cid: parts (GHSA-xvjh-v9c6-qcvc)', () => {
expect(inertBlobType('')).toBe('application/octet-stream');
});
it('refuses a type the Blob constructor would drop to an empty, sniffed type', () => {
// A TNEF/winmail.dat MIME tag is free text. new Blob() empties any type
// with a character outside U+0020-U+007E, and Firefox sniffs an untyped
// blob: document, so such a type must not count as inert.
for (const type of ['image/png\u0000', 'image/pngé', 'video/mp4\t', 'application/pdf\u0085']) {
expect(new Blob([], { type }).type).toBe('');
expect(isMimeTypeSafeForInlinePreview(type)).toBe(false);
expect(inertBlobType(type)).toBe('application/octet-stream');
}
});
it('re-types a fetched Blob without touching its bytes', async () => {
const html = new Blob(['<script>alert(1)</script>'], { type: 'text/html' });
const inert = toInertBlob(html);
+5 -1
View File
@@ -157,7 +157,11 @@ const INLINE_PREVIEW_UNSAFE_MIME_TYPES = new Set([
// XML variants would execute in our origin. Only an explicit allowlist of inert
// types is permitted; everything else must be downloaded.
export function isMimeTypeSafeForInlinePreview(type?: string): boolean {
const mimeType = type?.split(';')[0]?.trim().toLowerCase() || '';
// new Blob() drops a type with any character outside U+0020-U+007E to "",
// and Firefox sniffs an untyped blob: document. A winmail.dat MIME tag is
// free text, so judge only types the Blob keeps as written.
if (!type || !/^[\x20-\x7e]+$/.test(type)) return false;
const mimeType = type.split(';')[0]?.trim().toLowerCase() || '';
if (!mimeType) return false;
if (INLINE_PREVIEW_UNSAFE_MIME_TYPES.has(mimeType)) return false;
if (INLINE_PREVIEW_SAFE_MIME_TYPES.has(mimeType)) return true;