n8n-nodes-binalyze-air
Version:
Binalyze AIR nodes for automating DFIR with n8n workflows
754 lines • 29.1 kB
JavaScript
;
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