import { describe, it, expect } from 'vitest'; import { verifyFileSignature } from '../src/lib/file-signature.js'; // Helper: build a buffer from a leading byte signature plus optional trailing filler. function bytes(sig: number[], pad = 0): Buffer { return Buffer.concat([Buffer.from(sig), Buffer.alloc(pad, 0x20)]); } const PDF = bytes([0x25, 0x50, 0x44, 0x46, 0x2d, 0x31, 0x2e, 0x37]); // %PDF-1.7 const PNG = bytes([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a], 16); const JPEG = bytes([0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46], 16); describe('verifyFileSignature', () => { it('accepts a real PDF declared as application/pdf', () => { expect(verifyFileSignature(PDF, 'application/pdf')).toBe(true); }); it('accepts a real PNG declared as image/png', () => { expect(verifyFileSignature(PNG, 'image/png')).toBe(true); }); it('accepts a real JPEG declared as image/jpeg', () => { expect(verifyFileSignature(JPEG, 'image/jpeg')).toBe(true); }); it('rejects an HTML page spoofed as image/png', () => { const html = Buffer.from('
hi', 'utf8'); expect(verifyFileSignature(html, 'image/png')).toBe(false); }); it('rejects an HTML page spoofed as image/jpeg', () => { const html = Buffer.from('', 'utf8'); expect(verifyFileSignature(html, 'image/jpeg')).toBe(false); }); it('rejects a Windows executable (MZ header) spoofed as text/plain', () => { // MZ header (0x4D 0x5A) followed by a NUL — NUL bytes disqualify it as text. const exe = Buffer.from([0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00]); expect(verifyFileSignature(exe, 'text/plain')).toBe(false); }); it('rejects a PDF whose bytes are actually an executable', () => { const exe = Buffer.from([0x4d, 0x5a, 0x90, 0x00]); expect(verifyFileSignature(exe, 'application/pdf')).toBe(false); }); it('rejects an unknown / non-allowlisted declared MIME type', () => { expect(verifyFileSignature(PDF, 'application/x-shockwave-flash')).toBe(false); expect(verifyFileSignature(PDF, 'image/svg+xml')).toBe(false); }); it('accepts genuine text declared as text/plain', () => { const text = Buffer.from('Dear client, please find the attached invoice.\n', 'utf8'); expect(verifyFileSignature(text, 'text/plain')).toBe(true); }); it('rejects a buffer too short to contain the signature', () => { expect(verifyFileSignature(Buffer.from([0x25, 0x50]), 'application/pdf')).toBe(false); }); it('accepts a real WEBP image declared as image/webp', () => { // RIFF....WEBP const webp = Buffer.concat([ Buffer.from([0x52, 0x49, 0x46, 0x46]), Buffer.from([0x00, 0x00, 0x00, 0x00]), Buffer.from('WEBP', 'latin1'), ]); expect(verifyFileSignature(webp, 'image/webp')).toBe(true); }); });