67 lines
3.0 KiB
TypeScript
67 lines
3.0 KiB
TypeScript
|
|
// magic-bytes 单测(Plan 3 Task 4 Step 1):六类签名各正例 + 伪签名 null 例 +
|
|||
|
|
// SVG 大小写不敏感 + 窗口边界(1KB 外不检出)+ 二进制签名优先于文本特征。
|
|||
|
|
// 期望值全部手写字面量(与实现零共享——对拍而非引用)。
|
|||
|
|
import { describe, expect, it } from 'vitest'
|
|||
|
|
import { detectMediaType } from '../../apps/api/src/modules/import/magic-bytes.js'
|
|||
|
|
|
|||
|
|
const PNG_SIG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])
|
|||
|
|
|
|||
|
|
describe('detectMediaType 手写签名表', () => {
|
|||
|
|
it('六类二进制签名正例:PNG/JPEG/GIF87a/GIF89a/WEBP/PDF', () => {
|
|||
|
|
expect(detectMediaType(Buffer.concat([PNG_SIG, Buffer.from('rest-of-png')]))).toStrictEqual({
|
|||
|
|
type: 'image/png',
|
|||
|
|
svg: false,
|
|||
|
|
})
|
|||
|
|
expect(detectMediaType(Buffer.from([0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10]))).toStrictEqual({
|
|||
|
|
type: 'image/jpeg',
|
|||
|
|
svg: false,
|
|||
|
|
})
|
|||
|
|
expect(detectMediaType(Buffer.from('GIF87a-more-gif'))).toStrictEqual({ type: 'image/gif', svg: false })
|
|||
|
|
expect(detectMediaType(Buffer.from('GIF89a-more-gif'))).toStrictEqual({ type: 'image/gif', svg: false })
|
|||
|
|
expect(
|
|||
|
|
detectMediaType(Buffer.concat([Buffer.from('RIFF'), Buffer.from([0x24, 0x00, 0x00, 0x00]), Buffer.from('WEBPVP8 ')])),
|
|||
|
|
).toStrictEqual({ type: 'image/webp', svg: false })
|
|||
|
|
expect(detectMediaType(Buffer.from('%PDF-1.7\n%fake-payload'))).toStrictEqual({
|
|||
|
|
type: 'application/pdf',
|
|||
|
|
svg: false,
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
it('SVG 文本特征:大小写不敏感(<svg / <SVG / <Svg,含 xml 声明前导),svg=true', () => {
|
|||
|
|
expect(detectMediaType(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg"/>'))).toStrictEqual({
|
|||
|
|
type: 'image/svg+xml',
|
|||
|
|
svg: true,
|
|||
|
|
})
|
|||
|
|
expect(detectMediaType(Buffer.from('<?xml version="1.0"?><SVG onload="x()">'))).toStrictEqual({
|
|||
|
|
type: 'image/svg+xml',
|
|||
|
|
svg: true,
|
|||
|
|
})
|
|||
|
|
expect(detectMediaType(Buffer.from('<!-- c --><Svg width="1">'))).toStrictEqual({
|
|||
|
|
type: 'image/svg+xml',
|
|||
|
|
svg: true,
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
it('伪签名 / 纯文本 / 空缓冲 → null(未知签名不猜格式)', () => {
|
|||
|
|
expect(detectMediaType(Buffer.from('hello plain text note'))).toBe(null)
|
|||
|
|
expect(detectMediaType(Buffer.from([0x00, 0x01, 0x02, 0x03]))).toBe(null)
|
|||
|
|
expect(detectMediaType(Buffer.alloc(0))).toBe(null)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
it('RIFF 非 WEBP(WAV)不误报 webp → null', () => {
|
|||
|
|
expect(
|
|||
|
|
detectMediaType(Buffer.concat([Buffer.from('RIFF'), Buffer.from([0x24, 0x00, 0x00, 0x00]), Buffer.from('WAVEfmt ')])),
|
|||
|
|
).toBe(null)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
it('二进制签名优先:PNG 头 + 尾部 <svg 片段仍判 PNG(文本窗口只对非二进制生效)', () => {
|
|||
|
|
const sneaky = Buffer.concat([PNG_SIG, Buffer.from('<svg onload="alert(1)"> trailing')])
|
|||
|
|
expect(detectMediaType(sneaky)).toStrictEqual({ type: 'image/png', svg: false })
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
it('SVG 窗口 1KB 钉死:<svg 出现在 1KB 之后不检出 → null', () => {
|
|||
|
|
const beyond = Buffer.concat([Buffer.alloc(1200, 0x20), Buffer.from('<svg>')])
|
|||
|
|
expect(detectMediaType(beyond)).toBe(null)
|
|||
|
|
})
|
|||
|
|
})
|