import { BadRequestException } from '@nestjs/common'; import { execFile } from 'node:child_process'; import { promisify } from 'node:util'; const execFileAsync = promisify(execFile); export const MAX_INSPECTION_REPORT_REVISION_BYTES = 15 * 1024 * 1024; export const INSPECTION_REPORT_WORD_MIME = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; export interface UploadedInspectionReportRevisionFile { originalname: string; mimetype: string; size: number; buffer: Buffer; } function invalidFile(message: string): BadRequestException { return new BadRequestException({ code: 'INSPECTION_REPORT_REVISION_INVALID_FILE', message }); } export function inspectInspectionReportRevisionUpload(file: UploadedInspectionReportRevisionFile | undefined): void { if (!file?.buffer?.length) throw invalidFile('Debés adjuntar un archivo Word .docx'); if (file.size <= 0 || file.size > MAX_INSPECTION_REPORT_REVISION_BYTES) throw invalidFile('El Word corregido debe pesar hasta 15 MB'); if (!file.originalname.toLowerCase().endsWith('.docx')) throw invalidFile('La versión corregida debe ser un archivo .docx'); if (file.mimetype && file.mimetype !== INSPECTION_REPORT_WORD_MIME && file.mimetype !== 'application/octet-stream') throw invalidFile('El tipo de archivo no corresponde a un Word .docx'); if (file.buffer.length < 4 || file.buffer[0] !== 0x50 || file.buffer[1] !== 0x4b || file.buffer[2] !== 0x03 || file.buffer[3] !== 0x04) throw invalidFile('El archivo no tiene una estructura DOCX válida'); } export async function validateInspectionReportRevisionContainer(filePath: string): Promise { let stdout = ''; try { ({ stdout } = await execFileAsync('unzip', ['-Z1', filePath], { encoding: 'utf8', maxBuffer: 4 * 1024 * 1024 })); } catch { throw invalidFile('No se pudo validar la estructura interna del Word'); } const entries = stdout.split(/\r?\n/).map((item) => item.trim()).filter(Boolean); if (!entries.includes('[Content_Types].xml') || !entries.includes('word/document.xml')) throw invalidFile('El archivo no contiene la estructura mínima de un documento Word'); if (entries.some((entry) => /(^|\/)vbaProject\.bin$/i.test(entry) || /(^|\/)embeddings\//i.test(entry))) throw invalidFile('No se permiten macros ni objetos embebidos en las versiones del informe'); }