fix: support SVGZ (gzip-compressed SVG) in SVG-to-raster tool

This commit is contained in:
SnapOtter
2026-05-13 10:58:23 +08:00
parent 8637105bce
commit 5a487746d0
+33 -6
View File
@@ -12,7 +12,7 @@ import { formatZodErrors } from "../../lib/errors.js";
import { sanitizeFilename } from "../../lib/filename.js"; import { sanitizeFilename } from "../../lib/filename.js";
import { encodeJxl } from "../../lib/format-encoders.js"; import { encodeJxl } from "../../lib/format-encoders.js";
import { decodeHeic, encodeHeic } from "../../lib/heic-converter.js"; import { decodeHeic, encodeHeic } from "../../lib/heic-converter.js";
import { isSvgBuffer, sanitizeSvg } from "../../lib/svg-sanitize.js"; import { decompressSvgz, isSvgBuffer, sanitizeSvg } from "../../lib/svg-sanitize.js";
import { createWorkspace } from "../../lib/workspace.js"; import { createWorkspace } from "../../lib/workspace.js";
import { updateJobProgress } from "../progress.js"; import { updateJobProgress } from "../progress.js";
@@ -96,7 +96,7 @@ async function convertSvg(
break; break;
} }
const baseName = sanitizeFilename(filename).replace(/\.svg$/i, ""); const baseName = sanitizeFilename(filename).replace(/\.svgz?$/i, "");
return { buffer, filename: `${baseName}.${ext}`, ext }; return { buffer, filename: `${baseName}.${ext}`, ext };
} }
@@ -193,7 +193,27 @@ export function registerSvgToRaster(app: FastifyInstance) {
currentFile: file.filename, currentFile: file.filename,
}); });
if (!isSvgBuffer(file.buffer)) { let decompressed: Buffer;
try {
decompressed = decompressSvgz(file.buffer);
} catch (err) {
errors.push({
filename: file.filename,
error: err instanceof Error ? err.message : "Invalid SVGZ file",
});
completedFiles++;
updateJobProgress({
jobId,
status: "processing",
totalFiles: files.length,
completedFiles,
failedFiles: errors.length,
errors,
});
return;
}
if (!isSvgBuffer(decompressed)) {
errors.push({ filename: file.filename, error: "Not a valid SVG file" }); errors.push({ filename: file.filename, error: "Not a valid SVG file" });
completedFiles++; completedFiles++;
updateJobProgress({ updateJobProgress({
@@ -209,7 +229,7 @@ export function registerSvgToRaster(app: FastifyInstance) {
let sanitized: Buffer; let sanitized: Buffer;
try { try {
sanitized = sanitizeSvg(file.buffer); sanitized = sanitizeSvg(decompressed);
} catch (err) { } catch (err) {
errors.push({ errors.push({
filename: file.filename, filename: file.filename,
@@ -338,7 +358,7 @@ export function registerSvgToRaster(app: FastifyInstance) {
chunks.push(chunk); chunks.push(chunk);
} }
fileBuffer = Buffer.concat(chunks); fileBuffer = Buffer.concat(chunks);
filename = sanitizeFilename(part.filename ?? "output").replace(/\.svg$/i, ""); filename = sanitizeFilename(part.filename ?? "output").replace(/\.svgz?$/i, "");
} else if (part.fieldname === "settings") { } else if (part.fieldname === "settings") {
settingsRaw = part.value as string; settingsRaw = part.value as string;
} }
@@ -354,13 +374,20 @@ export function registerSvgToRaster(app: FastifyInstance) {
return reply.status(400).send({ error: "No SVG file provided" }); return reply.status(400).send({ error: "No SVG file provided" });
} }
try {
fileBuffer = decompressSvgz(fileBuffer);
} catch (err) {
return reply.status(400).send({
error: err instanceof Error ? err.message : "Invalid SVGZ file",
});
}
if (!isSvgBuffer(fileBuffer)) { if (!isSvgBuffer(fileBuffer)) {
return reply.status(400).send({ return reply.status(400).send({
error: "File is not a valid SVG. This tool only accepts SVG files.", error: "File is not a valid SVG. This tool only accepts SVG files.",
}); });
} }
// Sanitize SVG to prevent XXE, SSRF, and script injection
try { try {
fileBuffer = sanitizeSvg(fileBuffer); fileBuffer = sanitizeSvg(fileBuffer);
} catch (err) { } catch (err) {