UNPKG

n8n-nodes-tenable-community

Version:

n8n node for the Tenable One platform

171 lines (170 loc) 7.84 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TenableSCClient = void 0; /** * @file Client for interacting with the Tenable Security Center (SC) API. * Handles authentication and provides methods for all SC-related operations. */ const n8n_workflow_1 = require("n8n-workflow"); /** * @class TenableSCClient * @description Implements the client for the Tenable Security Center (SC) API. * This class provides a comprehensive set of methods to interact with various * resources within Tenable.sc, including vulnerability analysis, asset management, * and configuration. */ class TenableSCClient { /** * Creates an instance of the TenableSCClient. * @param {ITriggerFunctions | IExecuteFunctions} context The n8n context object, used for accessing credentials and helpers. */ constructor(context) { this.context = context; } /** * A private helper method to send authenticated requests to the Tenable.sc API. * It automatically attaches API keys and constructs the full request URL. * @private * @param {IHttpRequestOptions} options - The request options, including method, URL, body, and query string. * @returns {Promise<unknown>} A promise that resolves to the JSON response from the API. * @throws {NodeApiError} When the API returns an error, it is wrapped in a standard n8n error for consistent handling. */ async sendRequest(options) { const credentials = await this.context.getCredentials('tenableOneApi'); const baseUrl = credentials.scUrl; if (!baseUrl) { throw new n8n_workflow_1.NodeApiError(this.context.getNode(), { message: 'Tenable.sc URL is not configured in credentials.' }); } options.headers = Object.assign(Object.assign({}, options.headers), { 'X-ApiKeys': `accessKey=${credentials.scAccessKey};secretKey=${credentials.scSecretKey}` }); options.json = true; options.url = `${baseUrl}/rest/${options.url}`; try { const requestOptions = Object.assign(Object.assign({}, options), { timeout: 60000 }); return await this.context.helpers.httpRequest(requestOptions); } catch (error) { throw new n8n_workflow_1.NodeApiError(this.context.getNode(), { message: error.message }); } } /** * Exports both active and remediated vulnerabilities from Tenable.sc within a given time range. * @param {object} body The request body containing the time range. * @param {number} body.since The start time for the export (Unix timestamp). * @param {number} body.until The end time for the export (Unix timestamp). * @returns {Promise<unknown>} A promise that resolves to an object containing active and remediated vulnerabilities. */ async exportVulnerabilities(filters) { const credentials = await this.context.getCredentials('tenableOneApi'); const baseUrl = credentials.scUrl; const since = filters.since; const until = filters.until; const activeVulnerabilities = await this.exportVulnerabilitiesByType('cumulative', baseUrl, credentials, since, until); const remediatedVulnerabilities = await this.exportVulnerabilitiesByType('patched', baseUrl, credentials, since, until); return { active: activeVulnerabilities, remediated: remediatedVulnerabilities, }; } /** * A private helper to export vulnerabilities of a specific type (e.g., 'cumulative', 'patched'). * Handles pagination to retrieve all results. * @private * @param {string} type The type of vulnerabilities to export. * @param {string} baseUrl The base URL of the Tenable.sc instance. * @param {object} credentials The credentials for the Tenable.sc instance. * @param {string} credentials.scAccessKey The access key. * @param {string} credentials.scSecretKey The secret key. * @param {number} startTime The start time for the export (Unix timestamp). * @param {number} endTime The end time for the export (Unix timestamp). * @returns {Promise<ITenableVulnerability[]>} A promise that resolves to the list of vulnerabilities. */ async exportVulnerabilitiesByType(type, baseUrl, credentials, startTime, endTime) { const vulnerabilities = []; let offset = 0; const limit = 2000; let hasMore = true; while (hasMore) { const options = { method: 'POST', url: `${baseUrl}/rest/analysis`, headers: { 'X-ApiKeys': `accessKey=${credentials.scAccessKey};secretKey=${credentials.scSecretKey}`, }, body: { query: { type: type, startOffset: offset, endOffset: offset + limit, filters: [ { filterName: type === 'cumulative' ? 'lastSeen' : 'lastMitigated', operator: ':', value: `${startTime}-${endTime}`, }, ], }, sourceType: 'vulnerabilities', }, json: true, }; const response = await this.context.helpers.httpRequest(options); vulnerabilities.push(...response.response.results); if (response.response.results.length < limit) { hasMore = false; } offset += limit; } return vulnerabilities; } // ================================================================= // ACCEPT RISK RULE // ================================================================= /** * Retrieves all 'Accept Risk' rules. * @returns {Promise<unknown>} A promise that resolves to the list of rules. */ async getAcceptRiskRule() { return this.sendRequest({ method: 'GET', url: 'acceptRiskRule' }); } /** * Creates a new 'Accept Risk' rule. * @param {object} body The rule definition. * @returns {Promise<unknown>} A promise that resolves to the created rule. */ async createAcceptRiskRule(body) { return this.sendRequest({ method: 'POST', url: 'acceptRiskRule', body }); } /** * Retrieves a specific 'Accept Risk' rule by its ID. * @param {string} id The ID of the rule. * @returns {Promise<unknown>} A promise that resolves to the rule details. */ async getAcceptRiskRuleById(id) { return this.sendRequest({ method: 'GET', url: `acceptRiskRule/${id}` }); } /** * Updates an existing 'Accept Risk' rule. * @param {string} id The ID of the rule to update. * @param {object} body The fields to update. * @returns {Promise<unknown>} A promise that resolves to the updated rule. */ async updateAcceptRiskRule(id, body) { return this.sendRequest({ method: 'PATCH', url: `acceptRiskRule/${id}`, body }); } /** * Deletes an 'Accept Risk' rule. * @param {string} id The ID of the rule to delete. * @returns {Promise<unknown>} A promise that resolves to the deletion confirmation. */ async deleteAcceptRiskRule(id) { return this.sendRequest({ method: 'DELETE', url: `acceptRiskRule/${id}` }); } /** * Applies all 'Accept Risk' rules. * @returns {Promise<unknown>} A promise that resolves to the application confirmation. */ async applyAcceptRiskRule() { return this.sendRequest({ method: 'POST', url: 'acceptRiskRule/apply' }); } } exports.TenableSCClient = TenableSCClient;