n8n-nodes-nessus
Version:
n8n community node for Tenable Nessus vulnerability scanner integration
803 lines β’ 36.9 kB
JavaScript
;
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