5f06256271
Build & Push / Pipeline Tests (push) Failing after 1m58s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 58s
Test / API Unit Tests (push) Successful in 1m9s
Test / Homepage Unit Tests (push) Successful in 46s
Test / Carplace Unit Tests (push) Successful in 43s
Test / Admin Unit Tests (push) Successful in 41s
Test / Dashboard Unit Tests (push) Successful in 45s
Test / API Integration Tests (push) Failing after 1m9s
71 lines
3.5 KiB
TypeScript
71 lines
3.5 KiB
TypeScript
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(<html><svg>PK\u0003\u0004)</script>\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('<!doctype html><script>alert(1)</script>')
|
|
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<receipt>.pdf')).toBe('bank_receipt_.pdf')
|
|
})
|
|
})
|