/**
* 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 => `
${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}
| ${t.package} |
${t.issueType} |
${t.severity} |
${t.expected} |
${t.actual} |
${t.description} |
${issues.map(issue => `
| ${issue.packageName} |
${formatIssueType(issue.issueType, t)} |
${issue.severity.toUpperCase()} |
${issue.expected || '-'} |
${issue.actual || '-'} |
${issue.description} |
`).join('')}
`;
}
/**
* Generate suspicious scripts section
*/
function generateSuspiciousScripts(scripts: SuspiciousScriptFinding[], t: any): string {
return `
⚠️
${t.suspiciousScriptsTitle}
${scripts.map(script => `
${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}
| ${t.folder} |
${t.type} |
${t.ecosystem} |
${t.packages} |
${t.size} |
${t.filesScanned} |
${result.scannedFolders.map(folder => `
| ${folder.path} |
${folder.type} |
${folder.ecosystem} |
${folder.packageCount} |
${formatBytes(folder.totalSizeBytes)} |
${folder.filesScanned.toLocaleString()} |
`).join('')}
`;
}
/**
* 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 };