Mojo-Maniac/Cerberus-Backend
0
1/**2 * Diff Analyzer3 * Maps n8n vulnerability data to the format expected by the VSCode extension.4 * Falls back to basic diff detection if n8n returns empty vulnerability arrays.5 */6 7/**8 * Severity mapping from n8n types to extension severity levels9 */10const SEVERITY_MAP = {11 'SQL Injection': 'critical',12 'Command Injection': 'critical',13 'Insecure Deserialization': 'critical',14 'Hardcoded Credentials': 'high',15 'Path Traversal': 'high',16 'XSS (Cross-Site Scripting)': 'high',17 'Weak Cryptography': 'high',18 'Debug Mode Enabled': 'medium',19 'Insecure Random': 'medium',20 'Missing Input Validation': 'medium',21};22 23/**24 * Map n8n severity string to extension severity level25 */26function normalizeSeverity(severity, type) {27 if (!severity) return SEVERITY_MAP[type] || 'medium';28 const s = severity.toLowerCase();29 if (s === 'high' || s === 'critical') return SEVERITY_MAP[type] || 'high';30 if (s === 'medium') return 'medium';31 if (s === 'low') return 'low';32 return 'medium';33}34 35/**36 * Extract individual vulnerabilities from n8n response data.37 * Primary strategy: use n8n's per-vulnerability mappings directly.38 * Fallback: basic diff detection if n8n data is incomplete.39 *40 * @param {string} original - Original source code41 * @param {string} corrected - Corrected code from n8n42 * @param {string} filePath - File path for display43 * @param {Array} n8nVulnerabilities - Vulnerability array from n8n workflow44 * @param {Array} n8nVulnDetails - Vulnerability details from n8n (type + line)45 * @returns {Array} Vulnerability objects for the extension46 */47function extractVulnerabilities(original, corrected, filePath, n8nVulnerabilities = [], n8nVulnDetails = []) {48 49 // ── Strategy 1: Direct n8n vulnerability mapping ──────────────────────────50 if (n8nVulnerabilities && n8nVulnerabilities.length > 0) {51 console.log(`[DIFF] Mapping ${n8nVulnerabilities.length} vulnerabilities from n8n`);52 53 const vulns = n8nVulnerabilities.map(nv => {54 const originalCode = nv.original_code || nv.originalCode || '';55 const fixedCode = nv.fixed_code || nv.fixedCode || '';56 const lineNumber = nv.line_number || nv.line || 0;57 const type = nv.type || 'Security Issue';58 const severity = normalizeSeverity(nv.severity, type);59 const issueText = nv.issue_text || nv.fix_recommendation || `${type} detected`;60 61 // Resolve line number from code if not provided62 let line = lineNumber;63 if (!line && originalCode) {64 // Find the line by matching the trimmed code content line-by-line65 const originalLines = original.split('\n');66 const searchLines = originalCode.trim().split('\n');67 68 // Try to find exact match first69 for (let i = 0; i <= originalLines.length - searchLines.length; i++) {70 let match = true;71 for (let j = 0; j < searchLines.length; j++) {72 if (originalLines[i + j].trim() !== searchLines[j].trim()) {73 match = false;74 break;75 }76 }77 if (match) {78 line = i + 1; // Convert to 1-indexed79 break;80 }81 }82 83 // If no exact match, try finding by the first significant line84 if (!line && searchLines.length > 0) {85 const firstSignificantLine = searchLines[0].trim();86 if (firstSignificantLine) {87 for (let i = 0; i < originalLines.length; i++) {88 if (originalLines[i].trim() === firstSignificantLine) {89 line = i + 1; // Convert to 1-indexed90 console.warn(`[DIFF] Used fuzzy match for line number: ${line}`);91 break;92 }93 }94 }95 }96 }97 98 // Validate line number99 if (!line || line < 1) {100 console.error(`[DIFF] Invalid line number: ${line} for type: ${type}`);101 line = 1; // Fallback to line 1102 }103 104 const endLine = line + (originalCode ? originalCode.split('\n').length - 1 : 0);105 106 return {107 file: filePath,108 line,109 endLine,110 type,111 severity,112 description: `${type} at line ${line}: ${issueText}`,113 originalCode,114 fixedCode,115 status: 'analyzed',116 isFixed: false,117 result: fixedCode118 };119 });120 121 // Sort by line number122 vulns.sort((a, b) => a.line - b.line);123 return vulns;124 }125 126 // ── Strategy 2: Fallback — code changed but no vulnerability data ─────────127 if (original !== corrected) {128 console.log('[DIFF] No n8n vulnerability data, creating generic vulnerability from diff');129 return [{130 file: filePath,131 line: 1,132 endLine: original.split('\n').length,133 type: 'Security Issues',134 severity: 'medium',135 description: 'Multiple security improvements applied',136 originalCode: original,137 fixedCode: corrected,138 status: 'analyzed',139 isFixed: false,140 result: corrected141 }];142 }143 144 // No changes detected145 return [];146}147 148/**149 * Apply a specific vulnerability fix to the full file code.150 * Used by the /api/apply-individual-fix endpoint.151 *152 * @param {string} fullCode - Full file code153 * @param {Object} vulnerability - Vulnerability object with line, endLine, fixedCode154 * @returns {string} Code with the fix applied155 */156function applyIndividualFix(fullCode, vulnerability) {157 const lines = fullCode.split('\n');158 const fixedLines = vulnerability.fixedCode.split('\n');159 160 const startIdx = (vulnerability.line || 1) - 1;161 const endIdx = (vulnerability.endLine || vulnerability.line || 1) - 1;162 const deleteCount = endIdx - startIdx + 1;163 164 lines.splice(startIdx, deleteCount, ...fixedLines);165 166 return lines.join('\n');167}168 169module.exports = {170 extractVulnerabilities,171 applyIndividualFix,172 normalizeSeverity,173 SEVERITY_MAP174};175 