mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix(image): validate caire settings as integers (#680)
caire's -width/-height/-blur/-sobel flags are integer-only; a schema-valid float crashed the binary and surfaced as a corrupt-file 422. Reject fractional values at validation time with a settings-shaped 400. Fixes #672.
This commit is contained in:
@@ -16,12 +16,14 @@ import { InputValidationError } from "../../modality/contract.js";
|
||||
import { inputHandlerFor } from "../../modality/input-handler.js";
|
||||
import { registerToolProcessFn } from "../tool-factory.js";
|
||||
|
||||
// caire's -width/-height/-blur/-sobel flags are integer-only; a fractional
|
||||
// value makes the binary exit with a flag parse error.
|
||||
const settingsSchema = z.object({
|
||||
width: z.number().positive().optional(),
|
||||
height: z.number().positive().optional(),
|
||||
width: z.number().int().positive().optional(),
|
||||
height: z.number().int().positive().optional(),
|
||||
protectFaces: z.boolean().default(false),
|
||||
blurRadius: z.number().min(0).max(20).default(4),
|
||||
sobelThreshold: z.number().min(1).max(20).default(2),
|
||||
blurRadius: z.number().int().min(0).max(20).default(4),
|
||||
sobelThreshold: z.number().int().min(1).max(20).default(2),
|
||||
square: z.boolean().default(false),
|
||||
});
|
||||
|
||||
|
||||
@@ -57,6 +57,27 @@ describe("Content-Aware Resize", () => {
|
||||
expect([200, 422]).toContain(res.statusCode);
|
||||
}, 60_000);
|
||||
|
||||
it("rejects fractional values for caire's integer-only flags", async () => {
|
||||
for (const settings of [
|
||||
{ width: 100.5 },
|
||||
{ height: 80.25 },
|
||||
{ blurRadius: 2.5 },
|
||||
{ sobelThreshold: 10.5 },
|
||||
]) {
|
||||
const { body, contentType } = createMultipartPayload([
|
||||
{ name: "file", filename: "test.png", contentType: "image/png", content: PNG_200x150 },
|
||||
{ name: "settings", content: JSON.stringify(settings) },
|
||||
]);
|
||||
const res = await app.inject({
|
||||
method: "POST",
|
||||
url: "/api/v1/tools/image/content-aware-resize",
|
||||
headers: { authorization: `Bearer ${adminToken}`, "content-type": contentType },
|
||||
body,
|
||||
});
|
||||
expect(res.statusCode, JSON.stringify(settings)).toBe(400);
|
||||
}
|
||||
}, 60_000);
|
||||
|
||||
it("rejects requests without a file", async () => {
|
||||
const { body, contentType } = createMultipartPayload([
|
||||
{ name: "settings", content: JSON.stringify({ width: 150 }) },
|
||||
|
||||
Reference in New Issue
Block a user