n8n-nodes-tenable-community
Version:
n8n node for the Tenable One platform
108 lines (107 loc) • 4.36 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TenableCSClient = void 0;
/**
* @file Client for interacting with the Tenable Cloud Security (CS) API.
* Handles authentication and provides methods for all CS-related operations,
* which are primarily GraphQL-based.
*/
const n8n_workflow_1 = require("n8n-workflow");
/**
* @class TenableCSClient
* @description Implements the client for the Tenable Cloud Security (CS) API.
* This client is specialized for sending GraphQL queries to the CNS endpoint.
*/
class TenableCSClient {
/**
* Creates an instance of the TenableCSClient.
* @param {ITriggerFunctions | IExecuteFunctions} context The n8n context object for credentials and helpers.
*/
constructor(context) {
this.context = context;
}
/**
* Sends a GraphQL request to the Tenable Cloud Security API endpoint.
* @private
* @param {string} query The GraphQL query string.
* @param {Record<string, unknown>} variables The variables for the GraphQL query.
* @returns {Promise<IDataObject>} A promise that resolves to the API response data.
* @throws {NodeApiError} If the API call fails or returns errors in the response body.
*/
async sendGQLRequest(query, variables) {
var _a, _b, _c;
const credentials = await this.context.getCredentials('tenableOneApi');
const endpoint = 'https://cloud.tenable.com/cns/graphql';
const headers = {
'X-ApiKeys': `accessKey=${credentials.csApiKey}`,
};
const requestOptions = {
url: endpoint,
method: 'POST',
headers,
body: {
query,
variables,
},
json: true,
timeout: 60000,
};
try {
return await this.context.helpers.httpRequest(requestOptions);
}
catch (error) {
if (error instanceof n8n_workflow_1.NodeApiError) {
const errorDetails = error.cause ? (_a = error.cause.response) === null || _a === void 0 ? void 0 : _a.body : { message: error.message };
const errorMessage = ((_c = (_b = errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.errors) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.message) || (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.message) || 'No additional error details provided.';
throw new n8n_workflow_1.NodeApiError(this.context.getNode(), { message: `Tenable API Error: ${errorMessage}` });
}
throw new n8n_workflow_1.NodeApiError(this.context.getNode(), { message: error.message });
}
}
/**
* Retrieves a list of all assets from Tenable.cs, automatically handling pagination.
* @public
* @returns {Promise<ITenableAsset[]>} A promise that resolves to the complete list of assets.
*/
async listAssets() {
const query = `
query listAssets($filter: AssetFilter, $first: Int, $after: String) {
assets(filter: $filter, first: $first, after: $after) {
nodes {
id
name
type
tags
ipv4
fqdn
netbiosName
macAddress
operatingSystem
source
exposure {
severity
score
lastSeen
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`;
const allAssets = [];
let hasNextPage = true;
let after;
while (hasNextPage) {
const response = await this.sendGQLRequest(query, { after });
const assets = response.assets;
allAssets.push(...assets.nodes);
hasNextPage = assets.pageInfo.hasNextPage;
after = assets.pageInfo.endCursor;
}
return allAssets;
}
}
exports.TenableCSClient = TenableCSClient;