n8n-nodes-tenable-community
Version:
n8n node for the Tenable One platform
171 lines (170 loc) • 7.84 kB
JavaScript
;
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;