You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

55 lines
1.3 KiB

import fs from "node:fs";
/** 与 multer 白名单一致:仅 PNG / JPEG / WebP(RIFF…WEBP) */
export const IMAGE_MAGIC_MISMATCH_MESSAGE = "文件内容与真实格式不符,请上传 PNG、JPEG 或 WebP 图片";
function matchesAllowedRasterMagic(head: Uint8Array): boolean {
if (head.length < 12) {
return false;
}
// JPEG
if (head[0] === 0xff && head[1] === 0xd8 && head[2] === 0xff) {
return true;
}
// PNG
if (
head[0] === 0x89
&& head[1] === 0x50
&& head[2] === 0x4e
&& head[3] === 0x47
&& head[4] === 0x0d
&& head[5] === 0x0a
&& head[6] === 0x1a
&& head[7] === 0x0a
) {
return true;
}
// WebP (RIFF .... WEBP)
if (
head[0] === 0x52
&& head[1] === 0x49
&& head[2] === 0x46
&& head[3] === 0x46
&& head[8] === 0x57
&& head[9] === 0x45
&& head[10] === 0x42
&& head[11] === 0x50
) {
return true;
}
return false;
}
/** 读取文件头并校验魔数(不依赖客户端 Content-Type) */
export function assertDiskFileIsAllowedRasterImage(filePath: string): void {
const fd = fs.openSync(filePath, "r");
try {
const buf = Buffer.alloc(12);
const n = fs.readSync(fd, buf, 0, 12, 0);
if (n < 12 || !matchesAllowedRasterMagic(buf)) {
throw new Error(IMAGE_MAGIC_MISMATCH_MESSAGE);
}
} finally {
fs.closeSync(fd);
}
}