mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: add graceful error handling and SVG sanitization to image-to-pdf
Per-image try-catch with Sharp fallback for CLI-decoded formats (matching createToolRoute), SVG decompression/sanitization, and filename-specific error messages so users know which image failed and why.
This commit is contained in:
@@ -11,6 +11,7 @@ import { validateImageBuffer } from "../../lib/file-validation.js";
|
|||||||
import { sanitizeFilename } from "../../lib/filename.js";
|
import { sanitizeFilename } from "../../lib/filename.js";
|
||||||
import { decodeToSharpCompat, needsCliDecode } from "../../lib/format-decoders.js";
|
import { decodeToSharpCompat, needsCliDecode } from "../../lib/format-decoders.js";
|
||||||
import { decodeHeic } from "../../lib/heic-converter.js";
|
import { decodeHeic } from "../../lib/heic-converter.js";
|
||||||
|
import { decompressSvgz, sanitizeSvg } from "../../lib/svg-sanitize.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
|
|
||||||
const targetSizeSchema = z.object({
|
const targetSizeSchema = z.object({
|
||||||
@@ -185,14 +186,43 @@ export function registerImageToPdf(app: FastifyInstance) {
|
|||||||
|
|
||||||
const validation = await validateImageBuffer(buf, file.filename);
|
const validation = await validateImageBuffer(buf, file.filename);
|
||||||
if (!validation.valid) {
|
if (!validation.valid) {
|
||||||
return reply.status(400).send({ error: `Invalid image: ${validation.reason}` });
|
return reply.status(400).send({
|
||||||
|
error: `Invalid image "${file.filename}": ${validation.reason}`,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validation.format === "heif") {
|
if (validation.format === "heif") {
|
||||||
buf = await decodeHeic(buf);
|
try {
|
||||||
|
buf = await decodeHeic(buf);
|
||||||
|
} catch (err) {
|
||||||
|
return reply.status(422).send({
|
||||||
|
error: `Failed to decode HEIC file "${file.filename}"`,
|
||||||
|
details: err instanceof Error ? err.message : String(err),
|
||||||
|
});
|
||||||
|
}
|
||||||
} else if (needsCliDecode(validation.format)) {
|
} else if (needsCliDecode(validation.format)) {
|
||||||
const fileExt = file.filename.split(".").pop()?.toLowerCase();
|
try {
|
||||||
buf = await decodeToSharpCompat(buf, validation.format, fileExt);
|
const fileExt = file.filename.split(".").pop()?.toLowerCase();
|
||||||
|
buf = await decodeToSharpCompat(buf, validation.format, fileExt);
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
await sharp(buf).metadata();
|
||||||
|
} catch (err) {
|
||||||
|
return reply.status(422).send({
|
||||||
|
error: `Failed to decode ${validation.format.toUpperCase()} file "${file.filename}"`,
|
||||||
|
details: err instanceof Error ? err.message : String(err),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (validation.format === "svg") {
|
||||||
|
try {
|
||||||
|
buf = decompressSvgz(buf);
|
||||||
|
buf = sanitizeSvg(buf);
|
||||||
|
} catch (err) {
|
||||||
|
return reply.status(400).send({
|
||||||
|
error: `Invalid SVG "${file.filename}": ${err instanceof Error ? err.message : "unknown error"}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preparedBuffers.push(await autoOrient(buf));
|
preparedBuffers.push(await autoOrient(buf));
|
||||||
|
|||||||
Reference in New Issue
Block a user