9cfd2e4a64
contract.routes.ts Vertragsdokumente-Upload hatte bisher nur den PDF-Inhalts-Scan aus 68.1. JPG/PNG-Uploads waren ungeprüft, ohne canonical Rename – Pentester selbst attestiert "ohne Exploit-Pfad" (Download-Layer fängt's), aber inkonsistent zu allen anderen Upload-Pfaden. - Refactor: detectType + validateUploadedFile aus upload.routes.ts in neue Middleware uploadFileTypeValidator.ts ausgelagert (Single Source of Truth, ~90 Zeilen Duplikation entfällt). - contract.routes.ts: validateUploadedFile ersetzt scanUploadedPdfIfPresent → Magic-Byte + canonical Rename + PDF-Scan in einer Pipeline. - pdfUploadSafety.ts: scanUploadedPdfIfPresent entfernt (tot).
35 lines
1.3 KiB
TypeScript
35 lines
1.3 KiB
TypeScript
import { Request, Response, NextFunction } from 'express';
|
||
import fs from 'fs';
|
||
import { assertSafePdf } from '../utils/sanitize.js';
|
||
import { ApiError } from '../utils/apiError.js';
|
||
|
||
/**
|
||
* Strikte Variante: Datei MUSS eine PDF sein. Sonst 415. Für Routen, die
|
||
* ausschliesslich PDFs zulassen (z.B. Vollmacht-Upload, PDF-Templates).
|
||
*
|
||
* Routen, die auch JPG/PNG akzeptieren (z.B. contract.routes
|
||
* Vertragsdokumente), nutzen `validateUploadedFile` aus
|
||
* `uploadFileTypeValidator.ts` – das macht Magic-Byte für ALLE Typen +
|
||
* PDF-Scan in einer Pipeline.
|
||
*/
|
||
export function requireSafeUploadedPdf(req: Request, res: Response, next: NextFunction): void {
|
||
const file = (req as Request & { file?: Express.Multer.File }).file;
|
||
if (!file) {
|
||
next();
|
||
return;
|
||
}
|
||
try {
|
||
const buf = fs.readFileSync(file.path);
|
||
if (buf.length < 5 || buf.subarray(0, 5).toString('latin1') !== '%PDF-') {
|
||
throw new ApiError(415, 'Datei ist keine gültige PDF.');
|
||
}
|
||
assertSafePdf(buf);
|
||
next();
|
||
} catch (e) {
|
||
try { fs.unlinkSync(file.path); } catch { /* ignore */ }
|
||
const status = e instanceof ApiError ? e.statusCode : 415;
|
||
const message = e instanceof Error ? e.message : 'PDF ungültig';
|
||
res.status(status).json({ success: false, error: message });
|
||
}
|
||
}
|