feat: make all hardcoded limits configurable via env vars

- bodyLimit: conditional on MAX_UPLOAD_SIZE_MB (0 = 1GB practical max)
- rate limiting: disabled when RATE_LIMIT_PER_MIN=0
- shutdown timeout: 8s → 30s
- upload plugin: no fileSize/files cap when env=0
- session duration: configurable via SESSION_DURATION_HOURS (default 168h)
- login attempts: configurable via LOGIN_ATTEMPT_LIMIT
- batch/pipeline/svg-to-raster: skip guard when MAX_BATCH_SIZE=0
- pipeline steps: configurable via MAX_PIPELINE_STEPS (0 = unlimited)
- user-files: remove 200 hard cap
- stitch canvas: configurable via MAX_CANVAS_PIXELS (0 = unlimited)
- PDF pages: configurable via MAX_PDF_PAGES (0 = unlimited)
- SVG size: configurable via MAX_SVG_SIZE_MB (0 = unlimited)
- logo size: configurable via MAX_LOGO_SIZE_KB (default 2048)
- worker threads: auto-detect via resolveWorkerThreads (0 = auto)
- megapixels: skip validation when MAX_MEGAPIXELS=0
- seam carving: remove 1200px dimension cap
- concurrency: auto-detect via resolveConcurrency (0 = auto)
This commit is contained in:
ashim-hq
2026-04-20 21:50:17 +08:00
parent be254f9ca6
commit 6746989aa1
14 changed files with 57 additions and 81 deletions
+2 -1
View File
@@ -7,6 +7,7 @@ import type { FastifyInstance } from "fastify";
import * as mupdf from "mupdf";
import sharp from "sharp";
import { z } from "zod";
import { env } from "../../config.js";
import { formatZodErrors } from "../../lib/errors.js";
import { encodeHeic } from "../../lib/heic-converter.js";
import { createWorkspace } from "../../lib/workspace.js";
@@ -229,7 +230,7 @@ export function registerPdfToImage(app: FastifyInstance) {
return reply.status(400).send({ error: "Password-protected PDFs are not supported" });
}
const pageCount = doc.countPages();
const maxPages = Math.min(pageCount, 200);
const maxPages = env.MAX_PDF_PAGES > 0 ? Math.min(pageCount, env.MAX_PDF_PAGES) : pageCount;
const thumbnails: Array<{
page: number;
dataUrl: string;
+4 -4
View File
@@ -4,14 +4,13 @@ import { basename, join } from "node:path";
import type { FastifyInstance } from "fastify";
import sharp from "sharp";
import { z } from "zod";
import { env } from "../../config.js";
import { autoOrient } from "../../lib/auto-orient.js";
import { formatZodErrors } from "../../lib/errors.js";
import { validateImageBuffer } from "../../lib/file-validation.js";
import { ensureSharpCompat } from "../../lib/heic-converter.js";
import { createWorkspace } from "../../lib/workspace.js";
const MAX_CANVAS_PIXELS = 100_000_000;
const settingsSchema = z.object({
direction: z.enum(["horizontal", "vertical", "grid"]).default("horizontal"),
gridColumns: z.number().int().min(2).max(100).default(2),
@@ -180,9 +179,10 @@ export function registerStitch(app: FastifyInstance) {
}
}
if (canvasWidth * canvasHeight > MAX_CANVAS_PIXELS) {
const maxCanvasPixels = env.MAX_CANVAS_PIXELS > 0 ? env.MAX_CANVAS_PIXELS : Infinity;
if (canvasWidth * canvasHeight > maxCanvasPixels) {
return reply.status(422).send({
error: `Canvas too large: ${canvasWidth}x${canvasHeight} (${Math.round((canvasWidth * canvasHeight) / 1_000_000)}MP exceeds 100MP limit)`,
error: `Canvas too large: ${canvasWidth}x${canvasHeight} (${Math.round((canvasWidth * canvasHeight) / 1_000_000)}MP exceeds ${Math.round(maxCanvasPixels / 1_000_000)}MP limit)`,
});
}
+3 -2
View File
@@ -7,6 +7,7 @@ import PQueue from "p-queue";
import sharp from "sharp";
import { z } from "zod";
import { env } from "../../config.js";
import { resolveConcurrency } from "../../lib/env.js";
import { formatZodErrors } from "../../lib/errors.js";
import { sanitizeFilename } from "../../lib/filename.js";
import { decodeHeic, encodeHeic } from "../../lib/heic-converter.js";
@@ -135,7 +136,7 @@ export function registerSvgToRaster(app: FastifyInstance) {
return reply.status(400).send({ error: "No SVG files provided" });
}
if (files.length > env.MAX_BATCH_SIZE) {
if (env.MAX_BATCH_SIZE > 0 && files.length > env.MAX_BATCH_SIZE) {
return reply.status(400).send({
error: `Too many files. Maximum batch size is ${env.MAX_BATCH_SIZE}`,
});
@@ -157,7 +158,7 @@ export function registerSvgToRaster(app: FastifyInstance) {
}
const jobId = clientJobId || randomUUID();
const queue = new PQueue({ concurrency: env.CONCURRENT_JOBS });
const queue = new PQueue({ concurrency: resolveConcurrency(env) });
const results: ({ buffer: Buffer; filename: string } | null)[] = new Array(files.length).fill(
null,
);