import { createHash } from 'crypto'; import { ExifTool } from 'exiftool-vendored'; import imageSize from 'image-size'; import PDFParser from 'pdf2json'; import { detectFileType } from 'detect-file-type'; export class FileValidator { private exiftool: ExifTool; constructor() { this.exiftool = new ExifTool(); } async validateFile(file: Buffer, mimeType: string) { // Validação básica de integridade const basicValidation = await this.performBasicValidation(file); if (!basicValidation.valid) { return basicValidation; } // Validação específica por tipo switch (mimeType) { case 'application/pdf': return await this.validatePDF(file); case 'image/jpeg': case 'image/png': return await this.validateImage(file, mimeType); default: return { valid: false, error: 'Tipo de arquivo não suportado' }; } } private async performBasicValidation(file: Buffer) { // Verificar tamanho mínimo if (file.length < 100) { return { valid: false, error: 'Arquivo muito pequeno ou vazio' }; } // Verificar assinatura do arquivo const fileType = await detectFileType(file); if (!fileType) { return { valid: false, error: 'Tipo de arquivo não reconhecido' }; } return { valid: true }; } private async validatePDF(file: Buffer) { return new Promise((resolve) => { const pdfParser = new PDFParser(); pdfParser.on('pdfParser_dataReady', () => { resolve({ valid: true, metadata: pdfParser.getAllFieldsTypes() }); }); pdfParser.on('pdfParser_dataError', (error) => { resolve({ valid: false, error: `PDF inválido: ${error}` }); }); pdfParser.parseBuffer(file); }); } private async validateImage(file: Buffer, mimeType: string) { try { // Verificar dimensões const dimensions = imageSize(file); if (!dimensions.width || !dimensions.height) { return { valid: false, error: 'Dimensões da imagem inválidas' }; } // Extrair metadados EXIF const metadata = await this.exiftool.readBuffer(file); // Verificações específicas para JPEG if (mimeType === 'image/jpeg') { if (!metadata.FileType || metadata.FileType !== 'JPEG') { return { valid: false, error: 'Assinatura JPEG inválida' }; } } return { valid: true, metadata: { dimensions, exif: metadata } }; } catch (error) { return { valid: false, error: `Erro na validação da imagem: ${error.message}` }; } } async validateMetadata(metadata: any) { const requiredFields = ['userAgent', 'ipAddress', 'timestamp']; const missingFields = requiredFields.filter(field => !metadata[field]); if (missingFields.length > 0) { return { valid: false, error: `Campos obrigatórios ausentes: ${missingFields.join(', ')}` }; } return { valid: true }; } generateHashes(file: Buffer) { return { sha256: createHash('sha256').update(file).digest('hex'), sha512: createHash('sha512').update(file).digest('hex'), md5: createHash('md5').update(file).digest('hex'), blake2b: createHash('blake2b512').update(file).digest('hex'), // Hash adicional whirlpool: createHash('whirlpool').update(file).digest('hex'), // Hash adicional }; } async cleanup() { await this.exiftool.end(); } }