/** * Installed Dependencies Report Generator * Generates HTML report section for installed dependencies malware scan */ import { InstalledDependenciesScanResult, InstalledMalwareFinding, IntegrityIssue, SuspiciousScriptFinding } from '../dependencies/installed/types'; import { MalwareIndicator } from '../dependencies/types'; import { Severity } from '../types'; /** * Generate HTML section for installed dependencies analysis */ export function generateInstalledDependenciesSection( result: InstalledDependenciesScanResult, language: string = 'es' ): string { const t = getTranslations(language); return `

🔍 ${t.title}

${generateInstalledSummary(result, t)} ${result.malwareFindings.length > 0 ? generateMalwareFindings(result.malwareFindings, t) : ''} ${result.integrityIssues.length > 0 ? generateIntegrityIssues(result.integrityIssues, t) : ''} ${result.suspiciousScripts.length > 0 ? generateSuspiciousScripts(result.suspiciousScripts, t) : ''} ${generateScannedFolders(result, t)}
${getInstalledDepsStyles()} `; } /** * Generate summary section */ function generateInstalledSummary(result: InstalledDependenciesScanResult, t: any): string { const stats = result.stats; const totalIssues = stats.malwareFindingsCount + stats.integrityIssuesCount + stats.suspiciousScriptsCount; const statusClass = totalIssues === 0 ? 'status-secure' : stats.malwareFindingsCount > 0 ? 'status-critical' : 'status-warning'; const statusIcon = totalIssues === 0 ? '✅' : stats.malwareFindingsCount > 0 ? '🚨' : '⚠️'; const statusText = totalIssues === 0 ? t.noMalwareFound : stats.malwareFindingsCount > 0 ? t.malwareDetected : t.issuesFound; return `
${statusIcon} ${statusText}
${stats.totalPackagesFound} ${t.packagesScanned}
${stats.totalFilesScanned.toLocaleString()} ${t.filesScanned}
${stats.malwareFindingsCount} ${t.malwareFindings}
${stats.integrityIssuesCount} ${t.integrityIssues}
${formatDuration(stats.duration)} ${t.scanTime}
`; } /** * Generate malware findings section */ function generateMalwareFindings(findings: InstalledMalwareFinding[], t: any): string { const findingsByIndicator = groupByIndicator(findings); return `

🦠 ${t.malwareFindingsTitle}

${Object.entries(findingsByIndicator).map(([indicator, items]) => `

${getIndicatorIcon(indicator as MalwareIndicator)} ${getIndicatorName(indicator as MalwareIndicator, t)} (${items.length})

${items.map(finding => `
${finding.severity.toUpperCase()} ${finding.title} ${finding.confidence}% ${t.confidence}
${t.package}: ${finding.package.name}@${finding.package.version}
${t.file}: ${finding.filePath}
${finding.lineNumber ? `
${t.line}: ${finding.lineNumber}
` : ''}
${t.description}: ${finding.description}
${finding.codeSnippet ? `
${escapeHtml(finding.codeSnippet)}
` : ''}
💡 ${finding.recommendation}
${finding.standards.length > 0 ? `
${finding.standards.map(s => ` ${s.standard} ${s.id} `).join('')}
` : ''}
`).join('')}
`).join('')}
`; } /** * Generate integrity issues section */ function generateIntegrityIssues(issues: IntegrityIssue[], t: any): string { return `

🔐 ${t.integrityIssuesTitle}

${issues.map(issue => ` `).join('')}
${t.package} ${t.issueType} ${t.severity} ${t.expected} ${t.actual} ${t.description}
${issue.packageName} ${formatIssueType(issue.issueType, t)} ${issue.severity.toUpperCase()} ${issue.expected || '-'} ${issue.actual || '-'} ${issue.description}
`; } /** * Generate suspicious scripts section */ function generateSuspiciousScripts(scripts: SuspiciousScriptFinding[], t: any): string { return `

⚠️ ${t.suspiciousScriptsTitle}

${scripts.map(script => `
${script.severity.toUpperCase()} ${script.packageName} ${script.script.type}
${escapeHtml(script.script.command)}
${script.description}
${script.riskIndicators.length > 0 ? `
${t.riskIndicators}: ${script.riskIndicators.map(ri => ` ${ri} `).join('')}
` : ''}
`).join('')}
`; } /** * Generate scanned folders section */ function generateScannedFolders(result: InstalledDependenciesScanResult, t: any): string { return `

📁 ${t.scannedFolders}

${result.scannedFolders.map(folder => ` `).join('')}
${t.folder} ${t.type} ${t.ecosystem} ${t.packages} ${t.size} ${t.filesScanned}
${folder.path} ${folder.type} ${folder.ecosystem} ${folder.packageCount} ${formatBytes(folder.totalSizeBytes)} ${folder.filesScanned.toLocaleString()}
`; } /** * Get translations */ function getTranslations(language: string): any { const translations: Record = { es: { title: 'Análisis de Malware en Dependencias Instaladas', noMalwareFound: 'No se detectó malware en las dependencias instaladas', malwareDetected: '¡MALWARE DETECTADO en dependencias!', issuesFound: 'Se encontraron problemas en las dependencias', packagesScanned: 'Paquetes escaneados', filesScanned: 'Archivos analizados', malwareFindings: 'Hallazgos de malware', integrityIssues: 'Problemas de integridad', scanTime: 'Tiempo de escaneo', malwareFindingsTitle: 'Detecciones de Malware', integrityIssuesTitle: 'Problemas de Integridad', suspiciousScriptsTitle: 'Scripts Post-Instalación Sospechosos', scannedFolders: 'Carpetas Escaneadas', package: 'Paquete', file: 'Archivo', line: 'Línea', description: 'Descripción', confidence: 'confianza', issueType: 'Tipo', severity: 'Severidad', expected: 'Esperado', actual: 'Encontrado', folder: 'Carpeta', type: 'Tipo', ecosystem: 'Ecosistema', packages: 'Paquetes', size: 'Tamaño', riskIndicators: 'Indicadores de riesgo', // Indicator names backdoor: 'Puerta trasera', cryptominer: 'Criptominero', stealer: 'Robo de datos', loader: 'Cargador de malware', obfuscated: 'Código ofuscado', data_exfiltration: 'Exfiltración de datos', known_malware: 'Malware conocido', // Issue types version_mismatch: 'Versión diferente', hash_mismatch: 'Hash diferente', unexpected_package: 'Paquete inesperado', missing_package: 'Paquete faltante', tampered: 'Manipulado' }, en: { title: 'Installed Dependencies Malware Analysis', noMalwareFound: 'No malware detected in installed dependencies', malwareDetected: 'MALWARE DETECTED in dependencies!', issuesFound: 'Issues found in dependencies', packagesScanned: 'Packages scanned', filesScanned: 'Files analyzed', malwareFindings: 'Malware findings', integrityIssues: 'Integrity issues', scanTime: 'Scan time', malwareFindingsTitle: 'Malware Detections', integrityIssuesTitle: 'Integrity Issues', suspiciousScriptsTitle: 'Suspicious Post-Install Scripts', scannedFolders: 'Scanned Folders', package: 'Package', file: 'File', line: 'Line', description: 'Description', confidence: 'confidence', issueType: 'Type', severity: 'Severity', expected: 'Expected', actual: 'Found', folder: 'Folder', type: 'Type', ecosystem: 'Ecosystem', packages: 'Packages', size: 'Size', riskIndicators: 'Risk indicators', // Indicator names backdoor: 'Backdoor', cryptominer: 'Cryptominer', stealer: 'Data stealer', loader: 'Malware loader', obfuscated: 'Obfuscated code', data_exfiltration: 'Data exfiltration', known_malware: 'Known malware', // Issue types version_mismatch: 'Version mismatch', hash_mismatch: 'Hash mismatch', unexpected_package: 'Unexpected package', missing_package: 'Missing package', tampered: 'Tampered' } }; return translations[language] || translations.es; } /** * Get indicator icon */ function getIndicatorIcon(indicator: MalwareIndicator): string { const icons: Record = { [MalwareIndicator.BACKDOOR]: '🚪', [MalwareIndicator.CRYPTOMINER]: '⛏️', [MalwareIndicator.STEALER]: '🔓', [MalwareIndicator.LOADER]: '📥', [MalwareIndicator.OBFUSCATED]: '🔣', [MalwareIndicator.DATA_EXFILTRATION]: '📤', [MalwareIndicator.KNOWN_MALWARE]: '☠️' }; return icons[indicator] || '⚠️'; } /** * Get indicator name */ function getIndicatorName(indicator: MalwareIndicator, t: any): string { const key = indicator.toLowerCase(); return t[key] || indicator; } /** * Format issue type */ function formatIssueType(type: string, t: any): string { return t[type] || type.replace(/_/g, ' '); } /** * Group findings by indicator */ function groupByIndicator(findings: InstalledMalwareFinding[]): Record { const groups: Record = {}; for (const finding of findings) { const indicator = finding.indicators[0] || MalwareIndicator.KNOWN_MALWARE; if (!groups[indicator]) { groups[indicator] = []; } groups[indicator].push(finding); } return groups; } /** * Format bytes to human-readable */ function formatBytes(bytes: number): string { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; } /** * Format duration */ function formatDuration(ms: number): string { if (ms < 1000) return `${ms}ms`; if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`; return `${(ms / 60000).toFixed(1)}m`; } /** * Escape HTML */ function escapeHtml(text: string): string { return text .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } /** * Get CSS styles for installed deps section */ function getInstalledDepsStyles(): string { return ` `; } export default { generateInstalledDependenciesSection };