Files
cms-website/tests/unit/magic-bytes.test.ts
T
浅念 ed081ec477 feat(import): 媒体登记与安全校验
Plan 3 Task 4:media-writer(attachment 行三级对拍 + 内容行引用提取双事件消费)
+ magic-bytes 手写签名表(零新增依赖)。

- 三级对拍(前置事实 7):①uploads 相对路径清单精确命中 ②侧车 source_url→
  file_path→清单实体(精确 miss 按文件名候选,多候选歧义不自动选全列 issue)
  ③missing 只进报告不插行(sha256 NOT NULL 库层防线)
- 魔数校验:命中实体读存储副本头部实际字节——SVG 检出 status=quarantined 不进
  产物语义(引用不建 usage);未知签名 unsupported;扩展名声明 MIME 与检测不符
  → issue(按检测登记)
- usage 两阶段时序(WXR 文档序 items 先于 attachment):内容行提取引用 + 修订
  锚点(依赖 content-writer 先处理同事件——Task 6 编排顺序契约),finish 统一
  对 media_assets 反查(id→source_id / URL→source_url→public_path),顺序无关
- 悬空引用计数 mediaDanglingRefs 不静默(mini 203/204 钉死)
- counts 六键 media 前缀独占(勿复用 'skipped' 的键契约注记)
- 幂等:(site,source_url) 定向 onConflictDoNothing + usage 复合主键——重跑零增行

308 测试(296+6 单测+6 集成);typecheck/lint 三绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-21 18:38:10 +08:00

67 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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)
})
})