UNPKG

n8n-nodes-binalyze-air

Version:

Binalyze AIR nodes for automating DFIR with n8n workflows

754 lines 29.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getRepositories = exports.AcquisitionsOperations = void 0; exports.extractAcquisitionProfileId = extractAcquisitionProfileId; exports.isValidAcquisitionProfile = isValidAcquisitionProfile; exports.fetchAllAcquisitionProfiles = fetchAllAcquisitionProfiles; exports.getAcquisitionProfiles = getAcquisitionProfiles; exports.getAcquisitionProfilesOptions = getAcquisitionProfilesOptions; exports.executeAcquisitions = executeAcquisitions; const n8n_workflow_1 = require("n8n-workflow"); const helpers_1 = require("../utils/helpers"); const acquisitions_1 = require("../api/acquisitions/acquisitions"); const organizations_1 = require("./organizations"); const repositories_1 = require("./repositories"); Object.defineProperty(exports, "getRepositories", { enumerable: true, get: function () { return repositories_1.getRepositories; } }); exports.AcquisitionsOperations = [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['acquisitions'], }, }, options: [ { name: 'Assign Evidence Acquisition Task', value: 'assignEvidenceTask', description: 'Assign an evidence acquisition task by filter', action: 'Assign an evidence acquisition task', }, { name: 'Get Acquisition Profile', value: 'get', description: 'Retrieve a specific acquisition profile', action: 'Get an acquisition profile', }, ], default: 'get', }, { displayName: 'Organization', name: 'organizationIdForGet', type: 'resourceLocator', default: { mode: 'list', value: '' }, placeholder: 'Select an organization...', displayOptions: { show: { resource: ['acquisitions'], operation: ['get'], }, }, modes: [ { displayName: 'From List', name: 'list', type: 'list', placeholder: 'Select an organization...', typeOptions: { searchListMethod: 'getOrganizations', searchable: true, }, }, { displayName: 'By ID', name: 'id', type: 'string', validation: [ { type: 'regex', properties: { regex: '^[0-9]+$', errorMessage: 'Not a valid organization ID (must be numeric)', }, }, ], placeholder: 'Enter organization ID (e.g., 123)', }, { displayName: 'By Name', name: 'name', type: 'string', placeholder: 'Enter organization name', }, ], required: true, description: 'The organization that owns the acquisition profile', }, { displayName: 'Organization', name: 'organizationId', type: 'resourceLocator', default: { mode: 'list', value: '' }, placeholder: 'Select an organization...', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], }, }, modes: [ { displayName: 'From List', name: 'list', type: 'list', placeholder: 'Select an organization...', typeOptions: { searchListMethod: 'getOrganizations', searchable: true, }, }, { displayName: 'By ID', name: 'id', type: 'string', validation: [ { type: 'regex', properties: { regex: '^[0-9]+$', errorMessage: 'Not a valid organization ID (must be numeric)', }, }, ], placeholder: 'Enter organization ID (e.g., 123)', }, { displayName: 'By Name', name: 'name', type: 'string', placeholder: 'Enter organization name', }, ], required: true, description: 'The organization for the acquisition task', }, { displayName: 'Acquisition Profile', name: 'acquisitionProfileId', type: 'resourceLocator', default: { mode: 'list', value: '' }, placeholder: 'Select an acquisition profile...', displayOptions: { show: { resource: ['acquisitions'], operation: ['get'], }, }, modes: [ { displayName: 'From List', name: 'list', type: 'list', placeholder: 'Select an acquisition profile...', typeOptions: { searchListMethod: 'getAcquisitionProfiles', searchable: true, }, }, { displayName: 'By ID', name: 'id', type: 'string', validation: [ { type: 'regex', properties: { regex: '^[a-zA-Z0-9-_]+$', errorMessage: 'Not a valid acquisition profile ID (must contain only letters, numbers, hyphens, and underscores)', }, }, ], placeholder: 'Enter acquisition profile ID', }, ], required: true, description: 'The acquisition profile to operate on', }, { displayName: 'Case', name: 'caseId', type: 'resourceLocator', default: { mode: 'list', value: '' }, placeholder: 'Select a case...', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], }, }, modes: [ { displayName: 'From List', name: 'list', type: 'list', placeholder: 'Select a case...', typeOptions: { searchListMethod: 'getCases', searchable: true, }, }, { displayName: 'By ID', name: 'id', type: 'string', validation: [ { type: 'regex', properties: { regex: '^[a-zA-Z0-9-_]+$', errorMessage: 'Not a valid case ID (must contain only letters, numbers, hyphens, and underscores)', }, }, ], placeholder: 'Enter case ID', }, ], required: true, description: 'The case to assign the acquisition task to', }, { displayName: 'Acquisition Profile', name: 'acquisitionProfileIdForTask', type: 'resourceLocator', default: { mode: 'list', value: '' }, placeholder: 'Select an acquisition profile...', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], }, }, modes: [ { displayName: 'From List', name: 'list', type: 'list', placeholder: 'Select an acquisition profile...', typeOptions: { searchListMethod: 'getAcquisitionProfiles', searchable: true, }, }, { displayName: 'By ID', name: 'id', type: 'string', validation: [ { type: 'regex', properties: { regex: '^[a-zA-Z0-9-_]+$', errorMessage: 'Not a valid acquisition profile ID (must contain only letters, numbers, hyphens, and underscores)', }, }, ], placeholder: 'Enter acquisition profile ID', }, ], required: true, description: 'The acquisition profile to use for the task', }, { displayName: 'Task Name', name: 'taskName', type: 'string', default: '', placeholder: 'Enter task name (optional)', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], }, }, description: 'Optional name for the acquisition task', }, { displayName: 'Save To', name: 'saveToLocation', type: 'options', default: 'local', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], }, }, options: [ { name: 'Local', value: 'local', description: 'Save evidence to local storage on each platform', }, { name: 'Repository', value: 'repository', description: 'Save evidence to a configured evidence repository', }, ], description: 'Where to save the acquired evidence', }, { displayName: 'Evidence Repository', name: 'repositoryId', type: 'resourceLocator', default: { mode: 'list', value: '' }, placeholder: 'Select an evidence repository...', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], saveToLocation: ['repository'], }, }, modes: [ { displayName: 'From List', name: 'list', type: 'list', placeholder: 'Select an evidence repository...', typeOptions: { searchListMethod: 'getRepositories', searchable: true, }, }, { displayName: 'By ID', name: 'id', type: 'string', validation: [ { type: 'regex', properties: { regex: '^[a-zA-Z0-9-_]+$', errorMessage: 'Not a valid repository ID (must contain only letters, numbers, hyphens, and underscores)', }, }, ], placeholder: 'Enter repository ID', }, { displayName: 'By Name', name: 'name', type: 'string', placeholder: 'Enter repository name', }, ], required: true, description: 'The evidence repository to save the acquired evidence to', }, { displayName: 'Use Most Free Volume', name: 'useMostFreeVolume', type: 'boolean', default: true, displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], saveToLocation: ['local'], }, }, description: 'Whether to automatically select the volume with the most free space for evidence storage', }, { displayName: 'Windows Save Path', name: 'windowsPath', type: 'string', default: 'C:\\Binalyze\\AIR', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], saveToLocation: ['local'], useMostFreeVolume: [false], }, }, description: 'Local path on Windows systems where evidence will be saved', }, { displayName: 'Linux Save Path', name: 'linuxPath', type: 'string', default: 'opt/binalyze/air', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], saveToLocation: ['local'], useMostFreeVolume: [false], }, }, description: 'Local path on Linux systems where evidence will be saved', }, { displayName: 'macOS Save Path', name: 'macosPath', type: 'string', default: 'opt/binalyze/air', displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], saveToLocation: ['local'], useMostFreeVolume: [false], }, }, description: 'Local path on macOS systems where evidence will be saved', }, { displayName: 'Enable DRONE', name: 'enableDrone', type: 'boolean', default: true, displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], }, }, required: true, description: 'Whether to enable DRONE analysis with AutoPilot and MITRE ATT&CK detection', }, { displayName: 'Endpoint Filters (Required)', name: 'endpointFilters', type: 'collection', placeholder: 'Add Filter', default: {}, displayOptions: { show: { resource: ['acquisitions'], operation: ['assignEvidenceTask'], }, }, required: true, description: 'At least one filter must be defined to target specific endpoints', options: [ { displayName: 'Filter By Asset Name', name: 'assetName', type: 'string', default: '', placeholder: 'Enter asset name', description: 'Filter assets by name', }, { displayName: 'Filter By IP Address', name: 'ipAddress', type: 'string', default: '', placeholder: 'Enter IP address', description: 'Filter assets by IP address', }, { displayName: 'Filter By Management Status', name: 'managedStatus', type: 'multiOptions', default: [], placeholder: 'Select management status', options: [ { name: 'Managed', value: 'managed', }, { name: 'Unmanaged', value: 'unmanaged', }, ], description: 'Filter assets by management status', }, { displayName: 'Filter By Online Status', name: 'onlineStatus', type: 'multiOptions', default: [], placeholder: 'Select online status', options: [ { name: 'Online', value: 'online', }, { name: 'Offline', value: 'offline', }, ], description: 'Filter assets by online status', }, { displayName: 'Filter By Platform', name: 'platform', type: 'multiOptions', default: [], placeholder: 'Select platforms', options: [ { name: 'Windows', value: 'windows', }, { name: 'Linux', value: 'linux', }, { name: 'macOS', value: 'darwin', }, { name: 'AIX', value: 'aix', }, ], description: 'Filter assets by platform', }, { displayName: 'Filter By Search Term', name: 'searchTerm', type: 'string', default: '', placeholder: 'Enter search term', description: 'Filter assets by search term', }, { displayName: 'Filter By Tags', name: 'tags', type: 'string', default: '', placeholder: 'Enter comma-separated tags', description: 'Filter assets by tags (comma-separated)', }, ], }, ]; function extractAcquisitionProfileId(acquisitionProfile) { return (0, helpers_1.extractEntityId)(acquisitionProfile, 'acquisition profile'); } function isValidAcquisitionProfile(acquisitionProfile) { return (0, helpers_1.isValidEntity)(acquisitionProfile, ['name']); } async function fetchAllAcquisitionProfiles(context, credentials, organizationIds = '0', searchFilter, pageSize = 100) { try { const queryParams = { pageSize, }; if (searchFilter) { queryParams['search'] = searchFilter; } const response = await acquisitions_1.api.getAcquisitionProfiles(context, credentials, organizationIds, queryParams); return response.result.entities || []; } catch (error) { throw new Error(`Failed to fetch acquisition profiles: ${error instanceof Error ? error.message : String(error)}`); } } function getOrganizationIdFromContext(context) { try { const currentParams = context.getCurrentNodeParameters(); if (currentParams && currentParams.organizationIdForGet) { const orgResource = currentParams.organizationIdForGet; if (typeof orgResource === 'object') { if (orgResource.mode === 'id' || orgResource.mode === 'list') { return orgResource.value || '0'; } return '0'; } else if (typeof orgResource === 'string') { return orgResource; } } } catch (error) { } return '0'; } async function getAcquisitionProfiles(searchTerm) { try { const credentials = await (0, helpers_1.getAirCredentials)(this); const organizationIds = getOrganizationIdFromContext(this); const acquisitionProfiles = await fetchAllAcquisitionProfiles(this, credentials, organizationIds, searchTerm); return (0, helpers_1.createListSearchResults)(acquisitionProfiles, isValidAcquisitionProfile, (profile) => ({ name: profile.name, value: extractAcquisitionProfileId(profile), url: '', }), searchTerm); } catch (error) { const formattedError = (0, helpers_1.catchAndFormatError)(error, 'search acquisition profiles'); throw formattedError; } } async function getAcquisitionProfilesOptions() { try { const credentials = await (0, helpers_1.getAirCredentials)(this); const organizationIds = getOrganizationIdFromContext(this); const acquisitionProfiles = await fetchAllAcquisitionProfiles(this, credentials, organizationIds); return (0, helpers_1.createLoadOptions)(acquisitionProfiles, isValidAcquisitionProfile, (profile) => ({ name: profile.name, value: extractAcquisitionProfileId(profile), })); } catch (error) { const formattedError = (0, helpers_1.catchAndFormatError)(error, 'load acquisition profiles options'); throw formattedError; } } async function executeAcquisitions() { const items = this.getInputData(); const returnData = []; const credentials = await (0, helpers_1.getAirCredentials)(this); const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); for (let i = 0; i < items.length; i++) { try { let responseData; if (operation === 'get') { const acquisitionProfileId = this.getNodeParameter('acquisitionProfileId', i); const profileId = (0, helpers_1.normalizeAndValidateId)(acquisitionProfileId.value || acquisitionProfileId, 'Acquisition Profile ID'); responseData = await acquisitions_1.api.getAcquisitionProfileById(this, credentials, profileId); responseData = responseData.result; } else if (operation === 'assignEvidenceTask') { const organizationId = this.getNodeParameter('organizationId', i); const caseId = this.getNodeParameter('caseId', i); const acquisitionProfileId = this.getNodeParameter('acquisitionProfileIdForTask', i); const taskName = this.getNodeParameter('taskName', i); const endpointFilters = this.getNodeParameter('endpointFilters', i); const saveToLocation = this.getNodeParameter('saveToLocation', i); const repositoryId = saveToLocation === 'repository' ? this.getNodeParameter('repositoryId', i) : undefined; const useMostFreeVolume = saveToLocation === 'local' ? this.getNodeParameter('useMostFreeVolume', i) : undefined; const windowsPath = saveToLocation === 'local' && !useMostFreeVolume ? this.getNodeParameter('windowsPath', i) : undefined; const linuxPath = saveToLocation === 'local' && !useMostFreeVolume ? this.getNodeParameter('linuxPath', i) : undefined; const macosPath = saveToLocation === 'local' && !useMostFreeVolume ? this.getNodeParameter('macosPath', i) : undefined; const enableDrone = this.getNodeParameter('enableDrone', i); const hasFilter = Boolean(endpointFilters.searchTerm || endpointFilters.assetName || endpointFilters.ipAddress || (endpointFilters.platform && endpointFilters.platform.length > 0) || (endpointFilters.onlineStatus && endpointFilters.onlineStatus.length > 0) || (endpointFilters.managedStatus && endpointFilters.managedStatus.length > 0) || endpointFilters.tags); if (!hasFilter) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one endpoint filter must be provided for evidence acquisition task', { itemIndex: i }); } let orgId; if (organizationId.mode === 'name') { const orgIdString = await (0, organizations_1.findOrganizationByName)(this, credentials, organizationId.value); orgId = parseInt(orgIdString, 10); } else { orgId = parseInt(organizationId.value || organizationId, 10); } const taskData = { caseId: (0, helpers_1.normalizeAndValidateId)(caseId.value || caseId, 'Case ID'), acquisitionProfileId: (0, helpers_1.normalizeAndValidateId)(acquisitionProfileId.value || acquisitionProfileId, 'Acquisition Profile ID'), filter: { organizationIds: [orgId], }, }; if (taskName) { taskData.taskName = taskName; } taskData.taskConfig = { choice: 'use-custom-options', saveTo: { windows: { location: saveToLocation, useMostFreeVolume: useMostFreeVolume || true, directCollection: false, tmp: 'Binalyze\\AIR\\tmp', }, linux: { location: saveToLocation, useMostFreeVolume: useMostFreeVolume || true, directCollection: false, tmp: 'opt/binalyze/air/tmp', }, macos: { location: saveToLocation, useMostFreeVolume: useMostFreeVolume || true, directCollection: false, tmp: 'opt/binalyze/air/tmp', }, aix: { location: saveToLocation, useMostFreeVolume: useMostFreeVolume || true, tmp: 'opt/binalyze/air/tmp', }, }, }; taskData.droneConfig = { autoPilot: enableDrone, enabled: enableDrone, mitreEnabled: enableDrone, analyzers: [], keywords: [], minScore: 0, }; taskData.eventLogRecordsConfig = { startDate: null, endDate: null, maxEventCount: 0, }; if (saveToLocation === 'local') { taskData.taskConfig.saveTo.windows.path = windowsPath || 'C:\\Binalyze\\AIR'; taskData.taskConfig.saveTo.linux.path = linuxPath || 'opt/binalyze/air'; taskData.taskConfig.saveTo.macos.path = macosPath || 'opt/binalyze/air'; taskData.taskConfig.saveTo.aix.path = 'opt/binalyze/air'; } else if (saveToLocation === 'repository') { const repoId = (0, helpers_1.normalizeAndValidateId)(repositoryId.value || repositoryId, 'Repository ID'); taskData.taskConfig.saveTo.windows.repositoryId = repoId; taskData.taskConfig.saveTo.linux.repositoryId = repoId; taskData.taskConfig.saveTo.macos.repositoryId = repoId; taskData.taskConfig.saveTo.aix.repositoryId = repoId; } if (endpointFilters.searchTerm) taskData.filter.searchTerm = endpointFilters.searchTerm; if (endpointFilters.assetName) taskData.filter.name = endpointFilters.assetName; if (endpointFilters.ipAddress) taskData.filter.ipAddress = endpointFilters.ipAddress; if (endpointFilters.platform) taskData.filter.platform = endpointFilters.platform; if (endpointFilters.onlineStatus) taskData.filter.onlineStatus = endpointFilters.onlineStatus; if (endpointFilters.managedStatus) taskData.filter.managedStatus = endpointFilters.managedStatus; if (endpointFilters.tags) taskData.filter.tags = endpointFilters.tags.split(',').map((tag) => tag.trim()); responseData = await acquisitions_1.api.assignEvidenceAcquisitionTask(this, credentials, taskData); responseData = responseData.result; } else { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The operation "${operation}" is not supported for resource "${resource}"`); } const executionData = { json: responseData, pairedItem: { item: i, }, }; returnData.push(executionData); } catch (error) { (0, helpers_1.handleExecuteError)(this, error, i, returnData); } } return [returnData]; } //# sourceMappingURL=acquisitions.js.map