UNPKG

n8n-nodes-nessus

Version:

n8n community node for Tenable Nessus vulnerability scanner integration

803 lines β€’ 36.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Nessus = void 0; const n8n_workflow_1 = require("n8n-workflow"); const NessusApi_1 = require("./NessusApi"); class Nessus { constructor() { this.description = { displayName: 'Nessus', name: 'nessus', icon: 'file:nessus-icon.svg', group: ['security'], version: 1, description: 'Interact with the Nessus API', defaults: { name: 'Nessus', }, inputs: ["main"], outputs: ["main"], credentials: [ { name: 'nessusApi', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Folder', value: 'folder', }, { name: 'Plugin', value: 'plugin', }, { name: 'Policy', value: 'policy', }, { name: 'Scan', value: 'scan', }, { name: 'Session', value: 'session', }, ], default: 'scan', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['scan'], }, }, options: [ { name: 'Copy', value: 'copy', description: 'Copy a scan', action: 'Copy a scan', }, { name: 'Create', value: 'create', description: 'Create a new scan', action: 'Create a new scan', }, { name: 'Delete', value: 'delete', description: 'Delete a scan', action: 'Delete a scan', }, { name: 'Export', value: 'export', description: 'Export scan results', action: 'Export scan results', }, { name: 'Get Details', value: 'getDetails', description: 'Get details of a specific scan', action: 'Get scan details', }, { name: 'Launch', value: 'launch', description: 'Launch a scan', action: 'Launch a scan', }, { name: 'List', value: 'list', description: 'List all scans', action: 'List all scans', }, { name: 'Pause', value: 'pause', description: 'Pause a running scan', action: 'Pause a scan', }, { name: 'Resume', value: 'resume', description: 'Resume a paused scan', action: 'Resume a scan', }, { name: 'Stop', value: 'stop', description: 'Stop a running scan', action: 'Stop a scan', }, ], default: 'list', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['policy'], }, }, options: [ { name: 'Copy', value: 'copy', description: 'Copy a policy', action: 'Copy a policy', }, { name: 'Create', value: 'create', description: 'Create a new policy', action: 'Create a new policy', }, { name: 'Delete', value: 'delete', description: 'Delete a policy', action: 'Delete a policy', }, { name: 'Get Details', value: 'getDetails', description: 'Get details of a specific policy', action: 'Get policy details', }, { name: 'List', value: 'list', description: 'List all policies', action: 'List all policies', }, { name: 'List Templates', value: 'listTemplates', description: 'List available policy templates', action: 'List policy templates', }, { name: 'Update', value: 'update', description: 'Update an existing policy', action: 'Update a policy', }, ], default: 'list', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['folder'], }, }, options: [ { name: 'List', value: 'list', description: 'List all folders', action: 'List all folders', }, { name: 'Create', value: 'create', description: 'Create a new folder', action: 'Create a new folder', }, { name: 'Delete', value: 'delete', description: 'Delete a folder', action: 'Delete a folder', }, ], default: 'list', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['plugin'], }, }, options: [ { name: 'List Families', value: 'listFamilies', description: 'List all plugin families', action: 'List plugin families', }, { name: 'List Plugins in Family', value: 'listPluginsInFamily', description: 'List plugins in a specific family', action: 'List plugins in family', }, { name: 'Get Plugin Details', value: 'getPluginDetails', description: 'Get details of a specific plugin', action: 'Get plugin details', }, ], default: 'listFamilies', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['session'], }, }, options: [ { name: 'Get Details', value: 'getDetails', description: 'Get session details', action: 'Get session details', }, { name: 'Edit', value: 'edit', description: 'Edit session settings', action: 'Edit session', }, ], default: 'getDetails', }, { displayName: 'Scan Name or ID', name: 'scanId', type: 'options', typeOptions: { loadOptionsMethod: 'getScans', }, required: true, displayOptions: { show: { resource: ['scan'], operation: ['getDetails', 'launch', 'stop', 'pause', 'resume', 'delete', 'export', 'copy'], }, }, default: '', description: 'Select the scan to operate on. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', placeholder: 'Select a scan...', }, { displayName: 'Policy Name or ID', name: 'policyId', type: 'options', typeOptions: { loadOptionsMethod: 'getPolicies', }, required: true, displayOptions: { show: { resource: ['policy'], operation: ['getDetails', 'update', 'delete', 'copy'], }, }, default: '', description: 'Select the policy to operate on. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', placeholder: 'Select a policy...', }, { displayName: 'Folder Name or ID', name: 'folderId', type: 'options', typeOptions: { loadOptionsMethod: 'getFolders', }, required: true, displayOptions: { show: { resource: ['folder'], operation: ['delete'], }, }, default: '', description: 'Select the folder to delete. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', placeholder: 'Select a folder...', }, { displayName: 'Plugin Family Name or ID', name: 'familyId', type: 'options', typeOptions: { loadOptionsMethod: 'getPluginFamilies', }, required: true, displayOptions: { show: { resource: ['plugin'], operation: ['listPluginsInFamily'], }, }, default: '', description: 'Select the plugin family. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', placeholder: 'Select a plugin family...', }, { displayName: 'Plugin Name or ID', name: 'pluginId', type: 'options', typeOptions: { loadOptionsMethod: 'getPluginsInFamily', }, required: true, displayOptions: { show: { resource: ['plugin'], operation: ['getPluginDetails'], }, }, default: '', description: 'Select the plugin. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', placeholder: 'Select a plugin...', }, { displayName: 'Targets', name: 'targets', type: 'string', required: true, displayOptions: { show: { resource: ['scan'], operation: ['create'], }, }, default: '', description: 'IP addresses, ranges, or hostnames to scan', placeholder: '192.168.1.1, 192.168.1.0/24, example.com', }, { displayName: 'Scan Name', name: 'scanName', type: 'string', displayOptions: { show: { resource: ['scan'], operation: ['create'], }, }, default: '=Basic Scan - {{new Date().toISOString().split("T")[0]}}', description: 'Name of the scan (auto-generated if left empty)', }, { displayName: 'Policy Template Name or ID', name: 'policyUuid', type: 'options', typeOptions: { loadOptionsMethod: 'getPolicyTemplates', }, displayOptions: { show: { resource: ['scan'], operation: ['create'], }, }, default: '', description: 'Policy template to use (will auto-select Basic Network Scan if left empty). Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', placeholder: 'Select a policy template...', }, { displayName: 'Export Format', name: 'exportFormat', type: 'options', required: true, displayOptions: { show: { resource: ['scan'], operation: ['export'], }, }, options: [ { name: 'Nessus', value: 'nessus', }, { name: 'PDF', value: 'pdf', }, { name: 'HTML', value: 'html', }, { name: 'CSV', value: 'csv', }, ], default: 'nessus', description: 'Format for the exported scan results', }, { displayName: 'New Name', name: 'newName', type: 'string', displayOptions: { show: { resource: ['scan'], operation: ['copy'], }, }, default: '', description: 'Name for the copied scan (optional - will use original name with "Copy" suffix if not provided)', placeholder: 'My Scan Copy', }, { displayName: 'Folder Name', name: 'folderName', type: 'string', required: true, displayOptions: { show: { resource: ['folder'], operation: ['create'], }, }, default: '', description: 'Name of the folder to create', }, { displayName: 'Destination Folder Name or ID', name: 'destinationFolderId', type: 'options', typeOptions: { loadOptionsMethod: 'getFolders', }, displayOptions: { show: { resource: ['scan'], operation: ['copy'], }, }, default: '', description: 'Select the destination folder (optional). Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', placeholder: 'Select a folder...', }, { displayName: 'Alternative Targets', name: 'altTargets', type: 'string', displayOptions: { show: { resource: ['scan'], operation: ['launch'], }, }, default: '', description: 'Comma-separated list of alternative targets (optional)', }, ], }; this.methods = { loadOptions: { async getPolicyTemplates() { const nessusApi = new NessusApi_1.NessusApi(this); try { const templates = await nessusApi.listScanTemplates(); const options = templates.templates.map((template) => ({ name: template.title, value: template.uuid, description: template.description, })); options.sort((a, b) => { if (a.name.toLowerCase().includes('basic') || a.name.toLowerCase().includes('network')) return -1; if (b.name.toLowerCase().includes('basic') || b.name.toLowerCase().includes('network')) return 1; return a.name.localeCompare(b.name); }); return options; } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load policy templates: ${error.message}`); } }, async getScans() { const nessusApi = new NessusApi_1.NessusApi(this); try { const scans = await nessusApi.listScans(); const options = scans.scans.map((scan) => { const creationDate = scan.creation_date ? new Date(scan.creation_date * 1000).toLocaleDateString() : 'Unknown'; let statusText = scan.status || 'Unknown'; if (scan.status === 'running') statusText = '🟒 Running'; else if (scan.status === 'completed') statusText = 'βœ… Completed'; else if (scan.status === 'paused') statusText = '⏸️ Paused'; else if (scan.status === 'stopped') statusText = '⏹️ Stopped'; else if (scan.status === 'canceled') statusText = '❌ Canceled'; return { name: `${scan.name} (${statusText})`, value: scan.id, description: `ID: ${scan.id} | Created: ${creationDate} | Owner: ${scan.owner || 'Unknown'}`, }; }); options.sort((a, b) => { const aRunning = a.name.includes('🟒 Running'); const bRunning = b.name.includes('🟒 Running'); if (aRunning && !bRunning) return -1; if (!aRunning && bRunning) return 1; return a.name.localeCompare(b.name); }); return options; } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load scans: ${error.message}`); } }, async getPolicies() { const nessusApi = new NessusApi_1.NessusApi(this); try { const policies = await nessusApi.listPolicies(); if (!Array.isArray(policies) || policies.length === 0) { return []; } const options = policies.map((policy) => { const creationDate = policy.creation_date ? new Date(policy.creation_date * 1000).toLocaleDateString() : 'Unknown'; return { name: policy.name || policy.title || `Policy ${policy.id}`, value: policy.id, description: `ID: ${policy.id} | Created: ${creationDate} | Owner: ${policy.owner || 'Unknown'}`, }; }); options.sort((a, b) => a.name.localeCompare(b.name)); return options; } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load policies: ${error.message}`); } }, async getFolders() { const nessusApi = new NessusApi_1.NessusApi(this); try { const folders = await nessusApi.listFolders(); if (!Array.isArray(folders) || folders.length === 0) { return []; } const options = folders.map((folder) => ({ name: folder.name, value: folder.id, description: `ID: ${folder.id} | Type: ${folder.type || 'Unknown'}`, })); options.sort((a, b) => a.name.localeCompare(b.name)); return options; } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load folders: ${error.message}`); } }, async getPluginFamilies() { const nessusApi = new NessusApi_1.NessusApi(this); try { const families = await nessusApi.listPluginFamilies(); if (!Array.isArray(families) || families.length === 0) { return []; } const options = families.map((family) => ({ name: family.name, value: family.id, description: `ID: ${family.id} | Count: ${family.count || 0} plugins`, })); options.sort((a, b) => a.name.localeCompare(b.name)); return options; } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load plugin families: ${error.message}`); } }, async getPluginsInFamily() { const nessusApi = new NessusApi_1.NessusApi(this); try { const familyId = this.getNodeParameter('familyId'); if (!familyId) { return []; } const plugins = await nessusApi.listPluginsInFamily(parseInt(familyId)); if (!Array.isArray(plugins) || plugins.length === 0) { return []; } const options = plugins.map((plugin) => ({ name: `${plugin.name} (ID: ${plugin.id})`, value: plugin.id, description: `Risk: ${plugin.risk_factor || 'Unknown'} | Family: ${plugin.family_name || 'Unknown'}`, })); options.sort((a, b) => a.name.localeCompare(b.name)); return options; } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load plugins: ${error.message}`); } }, }, }; } async execute() { const items = this.getInputData(); const returnData = []; const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); const nessusApi = new NessusApi_1.NessusApi(this); for (let i = 0; i < items.length; i++) { try { let responseData; if (resource === 'scan') { if (operation === 'list') { responseData = await nessusApi.listScans(); } else if (operation === 'getDetails') { const scanId = parseInt(this.getNodeParameter('scanId', i)); responseData = await nessusApi.getScanDetails(scanId); } else if (operation === 'create') { const scanName = this.getNodeParameter('scanName', i); let policyUuid = this.getNodeParameter('policyUuid', i); const targets = this.getNodeParameter('targets', i); if (!policyUuid) { const templates = await nessusApi.listScanTemplates(); if (templates.templates && templates.templates.length > 0) { const sortedTemplates = templates.templates.sort((a, b) => { if (a.title.toLowerCase().includes('basic') || a.title.toLowerCase().includes('network')) return -1; if (b.title.toLowerCase().includes('basic') || b.title.toLowerCase().includes('network')) return 1; return a.title.localeCompare(b.title); }); policyUuid = sortedTemplates[0].uuid; } } const finalScanName = scanName || `Basic Scan - ${new Date().toISOString().split('T')[0]}`; const scanData = { uuid: policyUuid, settings: { name: finalScanName, text_targets: targets, enabled: false, }, }; responseData = await nessusApi.createScan(scanData); } else if (operation === 'launch') { const scanId = parseInt(this.getNodeParameter('scanId', i)); const altTargets = this.getNodeParameter('altTargets', i); const altTargetsList = altTargets ? altTargets.split(',').map(t => t.trim()) : undefined; responseData = await nessusApi.launchScan(scanId, altTargetsList); } else if (operation === 'stop') { const scanId = parseInt(this.getNodeParameter('scanId', i)); responseData = await nessusApi.stopScan(scanId); } else if (operation === 'pause') { const scanId = parseInt(this.getNodeParameter('scanId', i)); responseData = await nessusApi.pauseScan(scanId); } else if (operation === 'resume') { const scanId = parseInt(this.getNodeParameter('scanId', i)); responseData = await nessusApi.resumeScan(scanId); } else if (operation === 'delete') { const scanId = parseInt(this.getNodeParameter('scanId', i)); responseData = await nessusApi.deleteScan(scanId); } else if (operation === 'export') { const scanId = parseInt(this.getNodeParameter('scanId', i)); const exportFormat = this.getNodeParameter('exportFormat', i); responseData = await nessusApi.exportScan(scanId, exportFormat); } else if (operation === 'copy') { const scanId = parseInt(this.getNodeParameter('scanId', i)); const newName = this.getNodeParameter('newName', i); const destinationFolderId = this.getNodeParameter('destinationFolderId', i); const folderId = destinationFolderId ? parseInt(destinationFolderId) : undefined; responseData = await nessusApi.copyScan(scanId, folderId, newName || undefined); } } else if (resource === 'policy') { if (operation === 'list') { responseData = await nessusApi.listPolicies(); } else if (operation === 'getDetails') { const policyId = parseInt(this.getNodeParameter('policyId', i)); responseData = await nessusApi.getPolicyDetails(policyId); } else if (operation === 'delete') { const policyId = parseInt(this.getNodeParameter('policyId', i)); responseData = await nessusApi.deletePolicy(policyId); } else if (operation === 'copy') { const policyId = parseInt(this.getNodeParameter('policyId', i)); responseData = await nessusApi.copyPolicy(policyId); } else if (operation === 'listTemplates') { responseData = await nessusApi.listScanTemplates(); } } else if (resource === 'folder') { if (operation === 'list') { responseData = await nessusApi.listFolders(); } else if (operation === 'create') { const folderName = this.getNodeParameter('folderName', i); responseData = await nessusApi.createFolder(folderName); } else if (operation === 'delete') { const folderId = parseInt(this.getNodeParameter('folderId', i)); responseData = await nessusApi.deleteFolder(folderId); } } else if (resource === 'plugin') { if (operation === 'listFamilies') { responseData = await nessusApi.listPluginFamilies(); } else if (operation === 'listPluginsInFamily') { const familyId = parseInt(this.getNodeParameter('familyId', i)); responseData = await nessusApi.listPluginsInFamily(familyId); } else if (operation === 'getPluginDetails') { const pluginId = parseInt(this.getNodeParameter('pluginId', i)); responseData = await nessusApi.getPluginDetails(pluginId); } } else if (resource === 'session') { if (operation === 'getDetails') { responseData = await nessusApi.getSessionDetails(); } } returnData.push({ json: responseData }); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error.message }, pairedItem: i }); } else { if (error.context) { error.context.itemIndex = i; throw error; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i, }); } } } return [this.helpers.returnJsonArray(returnData)]; } } exports.Nessus = Nessus; //# sourceMappingURL=Nessus.node.js.map