From 5be2e73c8a9494b854c6ea13c89350b28c4f73de Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Mon, 23 Mar 2026 02:22:15 +0100 Subject: [PATCH] fix: use per-request upload limit from DB and fix silent truncation Reads max_upload_size_bytes from instance_settings per-request and passes it to request.file() so Fastify kills the stream at the admin's configured limit. Checks file.truncated to properly reject files that exceed the limit instead of saving corrupted data. --- packages/server/src/index.ts | 2 +- packages/server/src/routes/uploads.ts | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 9ead5f43..744a2630 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -61,7 +61,7 @@ async function main(): Promise { await app.register(multipart, { limits: { - fileSize: config.maxUploadSize, + fileSize: 500 * 1024 * 1024, // 500MB hard ceiling — actual limit enforced per-request }, }); diff --git a/packages/server/src/routes/uploads.ts b/packages/server/src/routes/uploads.ts index 762e9362..61926d54 100644 --- a/packages/server/src/routes/uploads.ts +++ b/packages/server/src/routes/uploads.ts @@ -38,7 +38,13 @@ export async function uploadRoutes(app: FastifyInstance): Promise { }, }, }, async (request, reply) => { - const data = await request.file(); + // Read dynamic upload limit from instance settings + const db = getDb(); + const settings = db.select({ maxUploadSizeBytes: schema.instanceSettings.maxUploadSizeBytes }) + .from(schema.instanceSettings).where(eq(schema.instanceSettings.id, 1)).get(); + const maxSize = settings?.maxUploadSizeBytes ?? config.maxUploadSize; + + const data = await request.file({ limits: { fileSize: maxSize } }); if (!data) { return reply.code(400).send({ error: 'No file provided', statusCode: 400 }); } @@ -56,18 +62,17 @@ export async function uploadRoutes(app: FastifyInstance): Promise { const writeStream = fs.createWriteStream(filepath); await pipeline(data.file, writeStream); - // Get file size - const stats = fs.statSync(filepath); - const size = stats.size; - - // Check size limit - if (size > config.maxUploadSize) { + // Check if file was truncated by multipart limit + if ((data.file as any).truncated) { fs.unlinkSync(filepath); return reply.code(413).send({ error: 'File too large', statusCode: 413 }); } + // Get file size + const stats = fs.statSync(filepath); + const size = stats.size; + const now = Date.now(); - const db = getDb(); // ─── Media processing ──────────────────────────────────────────────────── let thumbnailFilename: string | null = null;