mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
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:
@@ -90,7 +90,7 @@ export async function validateImageBuffer(
|
||||
const height = metadata.height ?? 0;
|
||||
const megapixels = (width * height) / 1_000_000;
|
||||
|
||||
if (megapixels > env.MAX_MEGAPIXELS) {
|
||||
if (env.MAX_MEGAPIXELS > 0 && megapixels > env.MAX_MEGAPIXELS) {
|
||||
return {
|
||||
valid: false,
|
||||
reason: `Image exceeds maximum size: ${megapixels.toFixed(1)}MP (limit: ${env.MAX_MEGAPIXELS}MP)`,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
const MAX_SVG_SIZE = 10 * 1024 * 1024; // 10MB
|
||||
import { env } from "../config.js";
|
||||
|
||||
/**
|
||||
* Sanitize an SVG buffer to prevent XXE, SSRF, and script injection.
|
||||
* Throws if the SVG exceeds the maximum allowed size.
|
||||
*/
|
||||
export function sanitizeSvg(buffer: Buffer): Buffer {
|
||||
if (buffer.length > MAX_SVG_SIZE) {
|
||||
throw new Error(`SVG exceeds maximum size of ${MAX_SVG_SIZE / 1024 / 1024}MB`);
|
||||
const maxSvgSize = env.MAX_SVG_SIZE_MB > 0 ? env.MAX_SVG_SIZE_MB * 1024 * 1024 : Infinity;
|
||||
if (buffer.length > maxSvgSize) {
|
||||
throw new Error(`SVG exceeds maximum size of ${env.MAX_SVG_SIZE_MB}MB`);
|
||||
}
|
||||
let svg = buffer.toString("utf-8");
|
||||
// Remove DOCTYPE (XXE prevention, including internal subsets)
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
* Uses Piscina (backed by worker_threads) so Sharp operations don't block
|
||||
* HTTP request handling, SSE streams, or health checks.
|
||||
*/
|
||||
import { availableParallelism } from "node:os";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import Piscina from "piscina";
|
||||
import { loadEnv, resolveWorkerThreads } from "./env.js";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
// Size the pool: leave 1 thread for the event loop, min 1 worker
|
||||
const maxThreads = Math.max(1, Math.min(availableParallelism() - 1, 4));
|
||||
const maxThreads = resolveWorkerThreads(loadEnv());
|
||||
|
||||
let pool: Piscina | null = null;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user