UNPKG

n8n-nodes-tenable-community

Version:

n8n node for the Tenable One platform

814 lines (813 loc) 37.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TenableVMClient = void 0; /** * @file Client for interacting with the Tenable Vulnerability Management API. * This file contains the TenableVMClient class, which is responsible for making all * API requests to the Tenable Vulnerability Management (formerly Tenable.io) platform. * It handles authentication, request signing, and provides well-defined methods * for each API resource. */ const n8n_workflow_1 = require("n8n-workflow"); /** * @class TenableVMClient * @description Implements a robust client for the Tenable Vulnerability Management API. * The methods are organized by API resource for clarity and maintainability. */ class TenableVMClient { /** * Creates an instance of the TenableVMClient. * @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 API. * It automatically attaches API keys and handles base URL construction and error parsing. * @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) { var _a, _b, _c; const credentials = await this.context.getCredentials('tenableOneApi'); const requestOptions = Object.assign(Object.assign({}, options), { headers: Object.assign(Object.assign({}, options.headers), { 'X-ApiKeys': `accessKey=${credentials.accessKey};secretKey=${credentials.secretKey}` }), json: true, url: `https://cloud.tenable.com/${options.url}`, 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 }); } } /** * A generic handler for long-running export jobs (e.g., vulnerabilities, assets). * This method encapsulates the standard "start, poll, download" logic for any * export-style operation, making the client much more maintainable and scalable. * @private * @param {object} params Parameters for the export job. * @param {string} params.startEndpoint The API endpoint to initiate the export. * @param {string} params.statusEndpoint The base endpoint to check the status of the export. * @param {string} params.downloadEndpoint The base endpoint to download the result chunks. * @param {IDataObject} params.startBody The body of the request to initiate the export. * @returns {Promise<IDataObject[]>} A promise that resolves to the combined list of items from all chunks. * @throws {NodeOperationError} If the export job fails or times out. */ async handleLongRunningExport(params) { const delay = (ms) => new Promise(res => setTimeout(res, ms)); const TIMEOUT_MS = 15 * 60 * 1000; // 15 minutes timeout const startTime = Date.now(); const exportJob = await this.sendRequest({ method: 'POST', url: params.startEndpoint, body: params.startBody }); const exportUuid = exportJob.export_uuid; if (!exportUuid) { throw new n8n_workflow_1.NodeOperationError(this.context.getNode(), 'Tenable API did not return an export UUID to track.'); } let statusResponse; while (true) { if (Date.now() - startTime > TIMEOUT_MS) { throw new n8n_workflow_1.NodeOperationError(this.context.getNode(), `Tenable export job timed out after 15 minutes.`); } statusResponse = await this.sendRequest({ method: 'GET', url: `${params.statusEndpoint}/${exportUuid}/status` }); if (statusResponse.status === 'finished' || statusResponse.status === 'FINISHED') { break; } if (statusResponse.status === 'error' || statusResponse.status === 'ERROR') { throw new n8n_workflow_1.NodeOperationError(this.context.getNode(), `Tenable export job failed with status: ${statusResponse.status}.`); } await delay(5000); } const allItems = []; if (statusResponse.chunks_available) { for (const chunkId of statusResponse.chunks_available) { const chunkData = await this.sendRequest({ method: 'GET', url: `${params.downloadEndpoint}/${exportUuid}/chunks/${chunkId}` }); if (Array.isArray(chunkData)) { allItems.push(...chunkData); } } } return allItems; } // ================================================================= // ASSETS // ================================================================= /** * Retrieves a list of assets. * @param {object} qs Query string parameters, e.g., for pagination. * @returns {Promise<{ assets: ITenableAsset[], total: number }>} The list of assets. */ async listAssets(qs = {}) { return this.sendRequest({ method: 'GET', url: 'assets', qs }); } /** * Retrieves details for a specific asset. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the asset. * @returns {Promise<ITenableAsset>} The asset details. */ async getAssetDetails(params) { return this.sendRequest({ method: 'GET', url: `assets/${params.id}` }); } /** * Retrieves information about a specific asset. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the asset. * @returns {Promise<IDataObject>} The asset information. */ async getAssetInfo(params) { return this.sendRequest({ method: 'GET', url: `assets/${params.id}/info` }); } /** * Retrieves tags for a specific asset. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the asset. * @returns {Promise<IDataObject>} The asset tags. */ async getAssetTags(params) { return this.sendRequest({ method: 'GET', url: `assets/${params.id}/tags` }); } /** * Imports assets into Tenable. * @param {IDataObject} body The request body containing asset data. * @returns {Promise<IDataObject>} The result of the import operation. */ async importAssets(body) { return this.sendRequest({ method: 'POST', url: 'assets/import', body }); } /** * Retrieves the status of an asset import job. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the import job. * @returns {Promise<IDataObject>} The import job status. */ async getImportJobStatus(params) { return this.sendRequest({ method: 'GET', url: `assets/import/${params.id}/status` }); } /** * Performs a bulk deletion of assets. * @param {IDataObject} body The request body containing the deletion query. * @returns {Promise<IDataObject>} The result of the bulk delete operation. */ async bulkDeleteAssets(body) { return this.sendRequest({ method: 'POST', url: 'assets/bulk-delete', body }); } // ================================================================= // VULNERABILITIES & EXPORTS // ================================================================= /** * Initiates and manages a long-running vulnerability export job. * @param {IDataObject} body The request body containing export filters. * @returns {Promise<ITenableVulnerability[]>} A promise resolving to an array of all vulnerabilities. */ async exportVulnerabilities(body) { return this.handleLongRunningExport({ startEndpoint: 'vulns/export', statusEndpoint: 'vulns/export', downloadEndpoint: 'vulns/export', startBody: body, }); } /** * Initiates and manages a long-running asset export job (v1 API). * @param {IDataObject} body The request body containing export filters. * @returns {Promise<ITenableAsset[]>} A promise resolving to an array of all assets. */ async exportAssetsV1(body) { return this.handleLongRunningExport({ startEndpoint: 'assets/export', statusEndpoint: 'assets/export', downloadEndpoint: 'assets/export', startBody: body, }); } /** * Retrieves the status of an asset export job. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the export job. * @returns {Promise<IDataObject>} The export job status. */ async getAssetsExportStatus(params) { return this.sendRequest({ method: 'GET', url: `assets/export/${params.id}/status` }); } /** * Downloads a specific chunk of an asset export job. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the export job. * @param {string} params.chunkId The ID of the chunk to download. * @returns {Promise<ITenableAsset[]>} The data for the specified chunk. */ async downloadAssetsChunk(params) { return this.sendRequest({ method: 'GET', url: `assets/export/${params.id}/chunks/${params.chunkId}` }); } /** * Cancels an in-progress asset export job. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the export job to cancel. * @returns {Promise<IDataObject>} The cancellation status. */ async cancelAssetExport(params) { return this.sendRequest({ method: 'POST', url: `assets/export/${params.id}/cancel` }); } // ================================================================= // SCANS // ================================================================= /** * Retrieves a list of scans. * @param {object} qs Query string parameters for filtering and pagination. * @returns {Promise<ITenableScan[]>} The list of scans. */ async listScans(qs = {}) { return this.sendRequest({ method: 'GET', url: 'scans', qs }); } /** * Creates a new scan configuration. * @param {IDataObject} body The request body defining the new scan. * @returns {Promise<ITenableScan>} The newly created scan object. */ async createScan(body) { return this.sendRequest({ method: 'POST', url: 'scans', body }); } /** * Retrieves details for a specific scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan. * @returns {Promise<ITenableScan>} The scan details. */ async getScanDetails(params) { return this.sendRequest({ method: 'GET', url: `scans/${params.id}` }); } /** * Updates an existing scan configuration. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to update. * @param {IDataObject} params.body The data to update. * @returns {Promise<IDataObject>} The updated scan object. */ async updateScan(params) { return this.sendRequest({ method: 'PUT', url: `scans/${params.id}`, body: params.body }); } /** * Deletes a scan configuration. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to delete. * @returns {Promise<IDataObject>} An empty object on success. */ async deleteScan(params) { return this.sendRequest({ method: 'DELETE', url: `scans/${params.id}` }); } /** * Launches a scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to launch. * @param {string[]} [params.alt_targets] An optional array of alternate targets to scan. * @returns {Promise<ITenableScan>} The launch confirmation details. */ async launchScan(params) { const body = params.alt_targets ? { alt_targets: params.alt_targets } : {}; return this.sendRequest({ method: 'POST', url: `scans/${params.id}/launch`, body }); } /** * Pauses a running scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to pause. * @returns {Promise<IDataObject>} An empty object on success. */ async pauseScan(params) { return this.sendRequest({ method: 'POST', url: `scans/${params.id}/pause` }); } /** * Resumes a paused scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to resume. * @returns {Promise<IDataObject>} An empty object on success. */ async resumeScan(params) { return this.sendRequest({ method: 'POST', url: `scans/${params.id}/resume` }); } /** * Stops a running scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to stop. * @returns {Promise<IDataObject>} An empty object on success. */ async stopScan(params) { return this.sendRequest({ method: 'POST', url: `scans/${params.id}/stop` }); } /** * Force stops a scan that is stuck in a stopping or publishing state. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to force-stop. * @returns {Promise<IDataObject>} An empty object on success. */ async forceStopScan(params) { return this.sendRequest({ method: 'POST', url: `scans/${params.id}/force-stop` }); } /** * Creates a copy of a scan configuration. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to copy. * @returns {Promise<ITenableScan>} The new, copied scan object. */ async copyScan(params) { return this.sendRequest({ method: 'POST', url: `scans/${params.id}/copy` }); } /** * Imports a scan from an uploaded file. * @param {IDataObject} body The request body containing the file reference. * @returns {Promise<IDataObject>} The result of the import operation. */ async importScan(body) { return this.sendRequest({ method: 'POST', url: 'scans/import', body }); } /** * Enables or disables the schedule for a scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan. * @param {IDataObject} params.body The request body, e.g., `{ "enabled": true }`. * @returns {Promise<IDataObject>} The updated schedule information. */ async toggleScanSchedule(params) { return this.sendRequest({ method: 'PUT', url: `scans/${params.id}/schedule`, body: params.body }); } /** * Retrieves the latest status of a scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan. * @returns {Promise<ITenableScan>} The latest scan status. */ async getLatestScanStatus(params) { return this.sendRequest({ method: 'GET', url: `scans/${params.id}/latest-status` }); } /** * Retrieves the progress of a running scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan. * @returns {Promise<IDataObject>} The scan progress percentage. */ async getScanProgress(params) { return this.sendRequest({ method: 'GET', url: `scans/${params.id}/progress` }); } /** * Updates the read status of a scan (marks it as read/unread). * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan. * @param {IDataObject} params.body The request body, e.g., `{ "read": true }`. * @returns {Promise<IDataObject>} An empty object on success. */ async updateScanReadStatus(params) { return this.sendRequest({ method: 'PUT', url: `scans/${params.id}/status`, body: params.body }); } /** * Retrieves the list of valid timezones for scheduling scans. * @returns {Promise<IDataObject>} The list of timezones. */ async listTimezones() { return this.sendRequest({ method: 'GET', url: 'scans/timezones' }); } // ================================================================= // SCAN HISTORY // ================================================================= /** * Retrieves the historical runs for a specific scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan. * @returns {Promise<ITenableScan[]>} The scan history. */ async getScanHistory(params) { return this.sendRequest({ method: 'GET', url: `scans/${params.id}/history` }); } /** * Retrieves details for a specific historical scan run. * @param {object} params The parameters for the request. * @param {string} params.scan_id The UUID of the parent scan. * @param {string} params.history_id The ID of the historical run. * @returns {Promise<IDataObject>} The details of the historical scan run. */ async getScanHistoryDetails(params) { return this.sendRequest({ method: 'GET', url: `scans/${params.scan_id}/history/${params.history_id}` }); } /** * Deletes a specific historical scan run. * @param {object} params The parameters for the request. * @param {string} params.scan_id The UUID of the parent scan. * @param {string} params.history_id The ID of the historical run to delete. * @returns {Promise<IDataObject>} An empty object on success. */ async deleteScanHistory(params) { return this.sendRequest({ method: 'DELETE', url: `scans/${params.scan_id}/history/${params.history_id}` }); } // ================================================================= // SCAN EXPORTS // ================================================================= /** * Initiates an export for a completed scan. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the scan to export. * @param {IDataObject} params.body The export options (format, chapters, etc.). * @returns {Promise<IDataObject>} The export job details. */ async requestScanExport(params) { return this.sendRequest({ method: 'POST', url: `scans/${params.id}/export`, body: params.body }); } /** * Checks the status of a pending scan export. * @param {object} params The parameters for the request. * @param {string} params.scan_id The UUID of the parent scan. * @param {string} params.file_id The ID of the export file. * @returns {Promise<IDataObject>} The export status. */ async getScanExportStatus(params) { return this.sendRequest({ method: 'GET', url: `scans/${params.scan_id}/export/${params.file_id}/status` }); } /** * Downloads a completed scan export file. * @param {object} params The parameters for the request. * @param {string} params.scan_id The UUID of the parent scan. * @param {string} params.file_id The ID of the export file. * @returns {Promise<unknown>} The file stream. */ async downloadScanExport(params) { const requestOptions = { method: 'GET', url: `scans/${params.scan_id}/export/${params.file_id}/download`, encoding: 'stream', // Important for handling file downloads }; return this.sendRequest(requestOptions); } // ================================================================= // SCAN RESULTS // ================================================================= /** * Retrieves details for a specific host within a scan. * @param {object} params The parameters for the request. * @param {string} params.scan_id The UUID of the scan. * @param {string} params.host_id The ID of the host. * @returns {Promise<IDataObject>} The host details. */ async getHostDetails(params) { return this.sendRequest({ method: 'GET', url: `scans/${params.scan_id}/hosts/${params.host_id}` }); } /** * Gets the full plugin output for a vulnerability on a host. * @param {object} params The parameters for the request. * @param {string} params.scan_id The UUID of the scan. * @param {string} params.host_id The ID of the host. * @param {string} params.plugin_id The ID of the plugin. * @returns {Promise<IDataObject>} The plugin output details. */ async getPluginOutput(params) { return this.sendRequest({ method: 'GET', url: `scans/${params.scan_id}/hosts/${params.host_id}/plugins/${params.plugin_id}` }); } /** * Downloads an attachment from a scan result. * @param {object} params The parameters for the request. * @param {string} params.scan_id The UUID of the scan. * @param {string} params.attachment_id The ID of the attachment. * @returns {Promise<unknown>} The file stream. */ async getScanAttachment(params) { const requestOptions = { method: 'GET', url: `scans/${params.scan_id}/attachments/${params.attachment_id}`, encoding: 'stream', }; return this.sendRequest(requestOptions); } // ================================================================= // POLICIES // ================================================================= /** * Retrieves a list of scan policies. * @param {object} qs Query string parameters for pagination. * @returns {Promise<IDataObject>} The list of policies. */ async listPolicies(qs = {}) { return this.sendRequest({ method: 'GET', url: 'policies', qs }); } /** * Creates a new scan policy. * @param {IDataObject} body The request body defining the new policy. * @returns {Promise<IDataObject>} The newly created policy object. */ async createPolicy(body) { return this.sendRequest({ method: 'POST', url: 'policies', body }); } /** * Retrieves details for a specific policy. * @param {object} params The parameters for the request. * @param {string} params.id The ID of the policy. * @returns {Promise<IDataObject>} The policy details. */ async getPolicyDetails(params) { return this.sendRequest({ method: 'GET', url: `policies/${params.id}` }); } /** * Updates an existing scan policy. * @param {object} params The parameters for the request. * @param {string} params.id The ID of the policy to update. * @param {IDataObject} params.body The data to update. * @returns {Promise<IDataObject>} The updated policy object. */ async updatePolicy(params) { return this.sendRequest({ method: 'PUT', url: `policies/${params.id}`, body: params.body }); } /** * Deletes a scan policy. * @param {object} params The parameters for the request. * @param {string} params.id The ID of the policy to delete. * @returns {Promise<IDataObject>} An empty object on success. */ async deletePolicy(params) { return this.sendRequest({ method: 'DELETE', url: `policies/${params.id}` }); } /** * Creates a copy of a scan policy. * @param {object} params The parameters for the request. * @param {string} params.id The ID of the policy to copy. * @returns {Promise<IDataObject>} The new, copied policy object. */ async copyPolicy(params) { return this.sendRequest({ method: 'POST', url: `policies/${params.id}/copy` }); } /** * Imports a policy from an uploaded file. * @param {IDataObject} body The request body containing the file reference. * @returns {Promise<IDataObject>} The result of the import operation. */ async importPolicy(body) { return this.sendRequest({ method: 'POST', url: 'policies/import', body }); } /** * Exports a policy to a file. * @param {object} params The parameters for the request. * @param {string} params.id The ID of the policy to export. * @returns {Promise<unknown>} The file stream. */ async exportPolicy(params) { const requestOptions = { method: 'GET', url: `policies/${params.id}/export`, encoding: 'stream', }; return this.sendRequest(requestOptions); } // ================================================================= // ASSET ATTRIBUTES // ================================================================= /** * Creates a new custom asset attribute definition. * @param {IDataObject} body The attribute definition. * @returns {Promise<IDataObject>} The created attribute object. */ async createAttribute(body) { return this.sendRequest({ method: 'POST', url: 'api/v3/assets/attributes', body }); } /** * Retrieves a list of all custom asset attribute definitions. * @returns {Promise<IDataObject>} The list of attributes. */ async listAttributes() { return this.sendRequest({ method: 'GET', url: 'api/v3/assets/attributes' }); } /** * Updates a custom asset attribute definition. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the attribute to update. * @param {IDataObject} params.body The data to update. * @returns {Promise<IDataObject>} The updated attribute object. */ async updateAttribute(params) { return this.sendRequest({ method: 'PUT', url: `api/v3/assets/attributes/${params.id}`, body: params.body }); } /** * Deletes a custom asset attribute definition. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the attribute to delete. * @returns {Promise<IDataObject>} An empty object on success. */ async deleteAttribute(params) { return this.sendRequest({ method: 'DELETE', url: `api/v3/assets/attributes/${params.id}` }); } /** * Assigns custom attribute values to a specific asset. * @param {object} params The parameters for the request. * @param {string} params.asset_id The UUID of the asset. * @param {IDataObject} params.body The attributes to assign. * @returns {Promise<IDataObject>} An empty object on success. */ async assignAttributesToAsset(params) { return this.sendRequest({ method: 'PUT', url: `api/v3/assets/${params.asset_id}/attributes`, body: params.body }); } /** * Retrieves the custom attributes assigned to a specific asset. * @param {object} params The parameters for the request. * @param {string} params.asset_id The UUID of the asset. * @returns {Promise<IDataObject>} The list of assigned attributes. */ async listAssetAttributes(params) { return this.sendRequest({ method: 'GET', url: `api/v3/assets/${params.asset_id}/attributes` }); } /** * Deletes all custom attribute assignments from a specific asset. * @param {object} params The parameters for the request. * @param {string} params.asset_id The UUID of the asset. * @returns {Promise<IDataObject>} An empty object on success. */ async deleteAssetAttributes(params) { return this.sendRequest({ method: 'DELETE', url: `api/v3/assets/${params.asset_id}/attributes` }); } // ================================================================= // REPORTS // ================================================================= /** * Creates a new report. * @param {IDataObject} body The report definition and filters. * @returns {Promise<IDataObject>} The report job details. */ async createReport(body) { return this.sendRequest({ method: 'POST', url: 'reports/export', body }); } /** * Retrieves the status of a report generation job. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the report job. * @returns {Promise<IDataObject>} The report job status. */ async getReportStatus(params) { return this.sendRequest({ method: 'GET', url: `reports/export/${params.id}/status` }); } /** * Downloads a completed report file. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the report job. * @returns {Promise<unknown>} The file stream. */ async downloadReport(params) { const requestOptions = { method: 'GET', url: `reports/export/${params.id}/download`, encoding: 'stream', }; return this.sendRequest(requestOptions); } // ================================================================= // FILTERS // ================================================================= /** * Retrieves the available filters for agent records. * @returns {Promise<IDataObject>} The list of agent filters. */ async listAgentFilters() { return this.sendRequest({ method: 'GET', url: 'filters/scans/agents' }); } /** * Retrieves the available filters for asset records. * @returns {Promise<IDataObject>} The list of asset filters. */ async listAssetFilters() { return this.sendRequest({ method: 'GET', url: 'filters/workbenches/assets' }); } /** * Retrieves the available filters for credential records. * @returns {Promise<IDataObject>} The list of credential filters. */ async listCredentialFilters() { return this.sendRequest({ method: 'GET', url: 'filters/credentials' }); } /** * Retrieves the available filters for report exports. * @returns {Promise<IDataObject>} The list of report filters. */ async listReportFilters() { return this.sendRequest({ method: 'GET', url: 'filters/reports/export' }); } /** * Retrieves the available filters for vulnerability records. * @returns {Promise<IDataObject>} The list of vulnerability filters. */ async listVulnerabilityFilters() { return this.sendRequest({ method: 'GET', url: 'filters/workbenches/vulnerabilities' }); } // ================================================================= // VULNERABILITIES (IMPORT) // ================================================================= /** * Imports vulnerability data into Tenable. * @param {IDataObject} body The vulnerability data to import. * @returns {Promise<IDataObject>} The result of the import operation. */ async importVulnerabilities(body) { return this.sendRequest({ method: 'POST', url: 'api/v2/vulnerabilities', body }); } // ================================================================= // SHARED COLLECTIONS // ================================================================= /** * Creates a new shared collection. * @param {IDataObject} body The definition of the new collection. * @returns {Promise<IDataObject>} The created shared collection object. */ async createSharedCollection(body) { return this.sendRequest({ method: 'POST', url: 'shared-collections', body }); } /** * Retrieves a list of shared collections. * @returns {Promise<IDataObject>} The list of shared collections. */ async listSharedCollections() { return this.sendRequest({ method: 'GET', url: 'shared-collections' }); } /** * Retrieves details for a specific shared collection. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the collection. * @returns {Promise<IDataObject>} The collection details. */ async getSharedCollection(params) { return this.sendRequest({ method: 'GET', url: `shared-collections/${params.id}` }); } /** * Updates a shared collection. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the collection to update. * @param {IDataObject} params.body The data to update. * @returns {Promise<IDataObject>} The updated collection object. */ async updateSharedCollection(params) { return this.sendRequest({ method: 'PUT', url: `shared-collections/${params.id}`, body: params.body }); } /** * Deletes a shared collection. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the collection to delete. * @returns {Promise<IDataObject>} An empty object on success. */ async deleteSharedCollection(params) { return this.sendRequest({ method: 'DELETE', url: `shared-collections/${params.id}` }); } /** * Adds scan configurations to a shared collection. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the collection. * @param {IDataObject} params.body The scan configs to add. * @returns {Promise<IDataObject>} An empty object on success. */ async addScanToSharedCollection(params) { return this.sendRequest({ method: 'POST', url: `shared-collections/${params.id}/scan-configs`, body: params.body }); } /** * Retrieves the scan configurations within a shared collection. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the collection. * @returns {Promise<IDataObject>} A list of scan configurations. */ async listScansInSharedCollection(params) { return this.sendRequest({ method: 'GET', url: `shared-collections/${params.id}/scan-configs` }); } /** * Removes scan configurations from a shared collection. * @param {object} params The parameters for the request. * @param {string} params.id The UUID of the collection. * @param {IDataObject} params.body The scan configs to remove. * @returns {Promise<IDataObject>} An empty object on success. */ async removeScanFromSharedCollection(params) { return this.sendRequest({ method: 'DELETE', url: `shared-collections/${params.id}/scan-configs`, body: params.body }); } // ================================================================= // USERS & PERMISSIONS // ================================================================= /** * Retrieves a list of users. * @param {object} qs Query string parameters for pagination. * @returns {Promise<IDataObject>} The list of users. */ async listUsers(qs = {}) { return this.sendRequest({ method: 'GET', url: 'users', qs }); } /** * Deletes a user. * @param {object} params The parameters for the request. * @param {string} params.id The ID of the user to delete. * @returns {Promise<IDataObject>} An empty object on success. */ async deleteUser(params) { return this.sendRequest({ method: 'DELETE', url: `users/${params.id}` }); } // ================================================================= // TAGS // ================================================================= /** * Retrieves all tag values. * @returns {Promise<IDataObject>} The list of tag values. */ async listTagValues() { return this.sendRequest({ method: 'GET', url: 'tags/values' }); } } exports.TenableVMClient = TenableVMClient;