39 lines
2.3 KiB
TypeScript
39 lines
2.3 KiB
TypeScript
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<void> {
|
|
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');
|
|
}
|