import { describe, expect, it } from 'vitest' import { assertPaymentEvidenceFile, sanitizeEvidenceFilename } from './paymentEvidence' function file(buffer: Buffer, originalname: string, mimetype: string): Express.Multer.File { return { buffer, originalname, mimetype, size: buffer.length } as Express.Multer.File } function png(width = 16, height = 16) { const head = Buffer.concat([ Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]), Buffer.from([0, 0, 0, 13]), Buffer.from('IHDR'), ]) const dimensions = Buffer.alloc(8) dimensions.writeUInt32BE(width, 0) dimensions.writeUInt32BE(height, 4) const ihdrRest = Buffer.alloc(9) const iend = Buffer.from([0, 0, 0, 0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82]) return Buffer.concat([head, dimensions, ihdrRest, iend]) } function jpeg(width = 16, height = 16) { return Buffer.from([ 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x0b, 0x08, (height >> 8) & 0xff, height & 0xff, (width >> 8) & 0xff, width & 0xff, 0x01, 0x01, 0x11, 0x00, 0xff, 0xd9, ]) } describe('payment evidence validation', () => { it('accepts a structurally bounded PDF by content', () => { const pdf = Buffer.from('%PDF-1.7\n1 0 obj\n<< /Type /Catalog >>\nendobj\n%%EOF') expect(assertPaymentEvidenceFile(file(pdf, 'receipt.pdf', 'application/pdf'))).toEqual({ mime: 'application/pdf', ext: '.pdf' }) }) it('accepts PDFs with trailing bytes after the EOF marker', () => { const pdf = Buffer.from('%PDF-1.7\n1 0 obj\n<< /Type /Catalog >>\nendobj\n%%EOF\n\u0000\u0000') expect(assertPaymentEvidenceFile(file(pdf, 'receipt.pdf', 'application/pdf'))).toEqual({ mime: 'application/pdf', ext: '.pdf' }) }) it('accepts PDFs that contain common byte sequences inside document content', () => { const pdf = Buffer.from('%PDF-1.7\n1 0 obj\n(PK\u0003\u0004)\nendobj\n%%EOF') expect(assertPaymentEvidenceFile(file(pdf, 'receipt.pdf', 'application/pdf'))).toEqual({ mime: 'application/pdf', ext: '.pdf' }) }) it('accepts valid evidence files reported with compatible browser MIME aliases', () => { const pdf = Buffer.from('%PDF-1.7\n1 0 obj\n<< /Type /Catalog >>\nendobj\n%%EOF') expect(assertPaymentEvidenceFile(file(pdf, 'receipt.pdf', 'application/octet-stream'))).toEqual({ mime: 'application/pdf', ext: '.pdf' }) expect(assertPaymentEvidenceFile(file(pdf, 'receipt.pdf', 'application/x-pdf'))).toEqual({ mime: 'application/pdf', ext: '.pdf' }) }) it('accepts valid image evidence with trailing bytes and common JPEG extensions', () => { expect(assertPaymentEvidenceFile(file(Buffer.concat([png(), Buffer.from('\n')]), 'receipt.png', 'image/x-png'))).toEqual({ mime: 'image/png', ext: '.png' }) expect(assertPaymentEvidenceFile(file(Buffer.concat([jpeg(), Buffer.from('\n')]), 'receipt.jfif', 'image/pjpeg'))).toEqual({ mime: 'image/jpeg', ext: '.jpg' }) }) it('rejects spoofed MIME types and active content', () => { const html = Buffer.from('') expect(() => assertPaymentEvidenceFile(file(html, 'receipt.pdf', 'application/pdf'))).toThrow(/suspicious/i) const png = Buffer.concat([Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]), Buffer.alloc(32)]) expect(() => assertPaymentEvidenceFile(file(png, 'receipt.pdf', 'application/pdf'))).toThrow(/valid PDF, JPEG, and PNG/i) }) it('sanitizes filenames without allowing path traversal', () => { expect(sanitizeEvidenceFilename('../../bank.pdf')).toBe('bank_receipt_.pdf') }) })