n8n-nodes-binalyze-air
Version:
Binalyze AIR nodes for automating DFIR with n8n workflows
891 lines • 33.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CasesOperations = void 0;
exports.extractCaseId = extractCaseId;
exports.isValidCase = isValidCase;
exports.resolveUserResourceLocator = resolveUserResourceLocator;
exports.resolveCaseResourceLocator = resolveCaseResourceLocator;
exports.findOrganizationByName = findOrganizationByName;
exports.getCases = getCases;
exports.getCasesOptions = getCasesOptions;
exports.getUsers = getUsers;
exports.executeCases = executeCases;
const helpers_1 = require("../utils/helpers");
const users_1 = require("./users");
const cases_1 = require("../api/cases/cases");
const organizations_1 = require("../api/organizations/organizations");
exports.CasesOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['cases'],
},
},
options: [
{
name: 'Change Owner',
value: 'changeOwner',
description: 'Change the owner of a case',
action: 'Change case owner',
},
{
name: 'Check Name',
value: 'checkName',
description: 'Check if a case name is available',
action: 'Check case name availability',
},
{
name: 'Close Case',
value: 'closeCase',
description: 'Close a specific case',
action: 'Close a case',
},
{
name: 'Create',
value: 'create',
description: 'Create a new case',
action: 'Create a case',
},
{
name: 'Get',
value: 'get',
description: 'Retrieve a specific case',
action: 'Get a case',
},
{
name: 'Get Activities',
value: 'getActivities',
description: 'Get activities for a specific case',
action: 'Get case activities',
},
{
name: 'Get Endpoints',
value: 'getEndpoints',
description: 'Get endpoints for a specific case',
action: 'Get case endpoints',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Retrieve many cases',
action: 'Get many cases',
},
{
name: 'Get Tasks',
value: 'getTasks',
description: 'Get tasks for a specific case',
action: 'Get case tasks',
},
{
name: 'Get Users',
value: 'getUsers',
description: 'Get users for a specific case',
action: 'Get case users',
},
],
default: 'getAll',
},
{
displayName: 'Case',
name: 'caseId',
type: 'resourceLocator',
default: { mode: 'id', value: '' },
placeholder: 'Select a case...',
displayOptions: {
show: {
resource: ['cases'],
operation: [
'get',
],
},
},
modes: [
{
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 ID of the case to retrieve',
},
{
displayName: 'Organization',
name: 'organizationId',
type: 'resourceLocator',
default: { mode: 'id', value: '0' },
placeholder: 'Select organization...',
displayOptions: {
show: {
resource: ['cases'],
operation: [
'getActivities',
'getEndpoints',
'getTasks',
'getUsers',
'changeOwner',
'closeCase',
],
},
},
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,\\s]+$',
errorMessage: 'Organization IDs must be comma-separated numbers. Use "0" for all organizations.',
},
},
],
placeholder: 'Enter organization IDs (comma-separated) or "0" for all',
},
{
displayName: 'By Name',
name: 'name',
type: 'string',
placeholder: 'Enter organization name',
},
],
required: true,
description: 'Organization to filter cases',
},
{
displayName: 'Case',
name: 'caseId',
type: 'resourceLocator',
default: { mode: 'list', value: '' },
placeholder: 'Select a case...',
displayOptions: {
show: {
resource: ['cases'],
operation: [
'getActivities',
'getEndpoints',
'getTasks',
'getUsers',
'changeOwner',
'closeCase'
],
},
},
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 operate on',
},
{
displayName: 'Case Name',
name: 'caseName',
type: 'string',
default: '',
placeholder: 'Enter case name',
displayOptions: {
show: {
resource: ['cases'],
operation: ['create', 'checkName'],
},
},
required: true,
description: 'The name of the case',
},
{
displayName: 'Organization',
name: 'organizationId',
type: 'resourceLocator',
default: { mode: 'id', value: '0' },
placeholder: 'Select organization...',
displayOptions: {
show: {
resource: ['cases'],
operation: ['create', 'getAll'],
},
},
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,\\s]+$',
errorMessage: 'Organization IDs must be comma-separated numbers. Use "0" for all organizations.',
},
},
],
placeholder: 'Enter organization IDs (comma-separated) or "0" for all',
},
{
displayName: 'By Name',
name: 'name',
type: 'string',
placeholder: 'Enter organization name',
},
],
required: true,
description: 'Organization for the case. For getAll operation, use "0" for all organizations.',
},
{
displayName: 'Owner User',
name: 'ownerUserId',
type: 'resourceLocator',
default: { mode: 'list', value: '' },
placeholder: 'Select a user...',
displayOptions: {
show: {
resource: ['cases'],
operation: ['create'],
},
},
modes: [
{
displayName: 'From List',
name: 'list',
type: 'list',
placeholder: 'Select a user...',
typeOptions: {
searchListMethod: 'getUsers',
searchable: true,
},
},
{
displayName: 'By ID',
name: 'id',
type: 'string',
validation: [
{
type: 'regex',
properties: {
regex: '^[a-zA-Z0-9-_]+$',
errorMessage: 'Not a valid user ID (must contain only letters, numbers, hyphens, and underscores)',
},
},
],
placeholder: 'Enter user ID (alphanumeric or GUID)',
},
{
displayName: 'By Username',
name: 'username',
type: 'string',
placeholder: 'Enter username or email',
},
],
required: true,
description: 'The user who will own the case',
},
{
displayName: 'New Owner User',
name: 'newOwnerUserId',
type: 'resourceLocator',
default: { mode: 'list', value: '' },
placeholder: 'Select a user...',
displayOptions: {
show: {
resource: ['cases'],
operation: ['changeOwner'],
},
},
modes: [
{
displayName: 'From List',
name: 'list',
type: 'list',
placeholder: 'Select a user...',
typeOptions: {
searchListMethod: 'getUsers',
searchable: true,
},
},
{
displayName: 'By ID',
name: 'id',
type: 'string',
validation: [
{
type: 'regex',
properties: {
regex: '^[a-zA-Z0-9-_]+$',
errorMessage: 'Not a valid user ID (must contain only letters, numbers, hyphens, and underscores)',
},
},
],
placeholder: 'Enter user ID (alphanumeric or GUID)',
},
{
displayName: 'By Username',
name: 'username',
type: 'string',
placeholder: 'Enter username or email',
},
],
required: true,
description: 'The new owner user for the case',
},
{
displayName: 'Visibility',
name: 'visibility',
type: 'options',
default: 'public-to-organization',
displayOptions: {
show: {
resource: ['cases'],
operation: ['create'],
},
},
options: [
{
name: 'Public to Organization',
value: 'public-to-organization',
},
{
name: 'Private to Users',
value: 'private-to-users',
},
],
required: true,
description: 'The visibility of the case',
},
{
displayName: 'Assigned User IDs',
name: 'assignedUserIds',
type: 'string',
default: '',
placeholder: 'Enter comma-separated user IDs (optional)',
displayOptions: {
show: {
resource: ['cases'],
operation: ['create'],
visibility: ['private-to-users'],
},
},
description: 'Comma-separated list of user IDs to assign to the case (required for private cases)',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['cases'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Page Number',
name: 'pageNumber',
type: 'number',
default: 1,
description: 'The page number to retrieve',
},
{
displayName: 'Page Size',
name: 'pageSize',
type: 'number',
default: 20,
description: 'The number of items per page',
},
{
displayName: 'Search Term',
name: 'searchTerm',
type: 'string',
default: '',
description: 'Search term to filter cases',
},
{
displayName: 'Filter By Status',
name: 'status',
type: 'options',
default: '',
options: [
{
name: 'All',
value: '',
},
{
name: 'Open',
value: 'open',
},
{
name: 'Closed',
value: 'closed',
},
{
name: 'Archived',
value: 'archived',
},
],
description: 'Filter cases by status',
},
],
},
];
function extractCaseId(caseItem) {
return (0, helpers_1.extractEntityId)(caseItem, '_id');
}
function isValidCase(caseItem) {
return (0, helpers_1.isValidEntity)(caseItem, ['_id']);
}
async function resolveUserResourceLocator(context, credentials, userResource, itemIndex, organizationIds) {
if (!userResource || typeof userResource !== 'object') {
throw new Error('Invalid user resource locator');
}
let userId;
if (userResource.mode === 'list' || userResource.mode === 'id') {
userId = userResource.value;
}
else if (userResource.mode === 'username') {
try {
const orgIds = organizationIds || '0';
userId = await (0, users_1.findUserByUsername)(context, credentials, userResource.value, orgIds);
}
catch (error) {
throw new Error(`Failed to find user by username: ${error instanceof Error ? error.message : String(error)}`);
}
}
else {
throw new Error('Invalid user selection mode');
}
return (0, helpers_1.normalizeAndValidateId)(userId, 'User ID');
}
async function resolveCaseResourceLocator(context, caseResource, itemIndex) {
if (!caseResource || typeof caseResource !== 'object') {
throw new Error('Invalid case resource locator');
}
let caseId;
if (caseResource.mode === 'list' || caseResource.mode === 'id') {
caseId = caseResource.value;
}
else {
throw new Error('Invalid case selection mode');
}
return (0, helpers_1.normalizeAndValidateId)(caseId, 'Case ID');
}
function getOrganizationIdFromContext(context) {
try {
const currentParams = context.getCurrentNodeParameters();
if (currentParams && currentParams.organizationId) {
const orgResource = currentParams.organizationId;
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 findOrganizationByName(context, credentials, organizationName) {
try {
const organizations = await organizations_1.api.getOrganizations(context, credentials, {
pageSize: 100,
searchTerm: organizationName
});
if (!organizations.success || !organizations.result || !organizations.result.entities) {
throw new Error('Failed to fetch organizations or invalid response structure');
}
const matchingOrg = organizations.result.entities.find((org) => org.name && org.name.toLowerCase() === organizationName.toLowerCase());
if (!matchingOrg) {
throw new Error(`Organization with name "${organizationName}" not found`);
}
return String(matchingOrg._id);
}
catch (error) {
throw new Error(`Failed to find organization by name: ${error instanceof Error ? error.message : String(error)}`);
}
}
async function getCases(filter) {
var _a;
const credentials = await (0, helpers_1.getAirCredentials)(this);
try {
let organizationIds = '0';
try {
const currentParams = this.getCurrentNodeParameters();
if (currentParams && currentParams.organizationId) {
const organizationId = currentParams.organizationId;
if (typeof organizationId === 'string') {
organizationIds = organizationId;
}
else if (organizationId && typeof organizationId === 'object') {
if (organizationId.mode === 'id' || organizationId.mode === 'list') {
organizationIds = organizationId.value || '0';
}
else if (organizationId.mode === 'name' && organizationId.value) {
try {
organizationIds = await findOrganizationByName(this, credentials, organizationId.value);
}
catch (error) {
organizationIds = '0';
}
}
}
}
}
catch (error) {
}
const response = await cases_1.api.getCases(this, credentials, organizationIds, {
pageSize: 100,
searchTerm: filter
});
(0, helpers_1.validateApiResponse)(response, 'Failed to fetch cases');
if (!((_a = response.result) === null || _a === void 0 ? void 0 : _a.entities)) {
return { results: [] };
}
return (0, helpers_1.createListSearchResults)(response.result.entities, isValidCase, (caseItem) => ({
name: caseItem.name || 'Unnamed Case',
value: extractCaseId(caseItem),
}), filter);
}
catch (error) {
if (error instanceof Error) {
throw error;
}
throw new Error('Failed to fetch cases for selection');
}
}
async function getCasesOptions() {
var _a;
const credentials = await (0, helpers_1.getAirCredentials)(this);
try {
let organizationIds = '0';
try {
const currentParams = this.getCurrentNodeParameters();
if (currentParams && currentParams.organizationId) {
const organizationId = currentParams.organizationId;
if (typeof organizationId === 'string') {
organizationIds = organizationId;
}
else if (organizationId && typeof organizationId === 'object') {
if (organizationId.mode === 'id' || organizationId.mode === 'list') {
organizationIds = organizationId.value || '0';
}
else if (organizationId.mode === 'name' && organizationId.value) {
try {
organizationIds = await findOrganizationByName(this, credentials, organizationId.value);
}
catch (error) {
organizationIds = '0';
}
}
}
}
}
catch (error) {
}
const response = await cases_1.api.getCases(this, credentials, organizationIds, { pageSize: 100 });
(0, helpers_1.validateApiResponse)(response, 'Failed to fetch cases');
if (!((_a = response.result) === null || _a === void 0 ? void 0 : _a.entities)) {
return [];
}
return (0, helpers_1.createLoadOptions)(response.result.entities, isValidCase, (caseItem) => ({
name: caseItem.name || 'Unnamed Case',
value: extractCaseId(caseItem),
}));
}
catch (error) {
if (error instanceof Error) {
throw error;
}
throw new Error('Failed to fetch cases options');
}
}
async function getUsers(filter) {
try {
const credentials = await (0, helpers_1.getAirCredentials)(this);
const organizationIds = getOrganizationIdFromContext(this);
const allUsers = await (0, users_1.fetchAllUsers)(this, credentials, organizationIds, filter);
return (0, helpers_1.createListSearchResults)(allUsers, users_1.isValidUser, (user) => ({
name: user.username || user.email || `User ${(0, users_1.extractUserId)(user)}`,
value: (0, users_1.extractUserId)(user),
url: user.url || '',
}), filter);
}
catch (error) {
if (error instanceof Error) {
throw error;
}
throw new Error('Failed to fetch users for selection');
}
}
async function executeCases() {
var _a;
const items = this.getInputData();
const returnData = [];
const operation = this.getNodeParameter('operation', 0);
const credentials = await (0, helpers_1.getAirCredentials)(this);
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
try {
let responseData;
switch (operation) {
case 'getAll':
responseData = await executeGetAllCases.call(this, credentials, itemIndex);
break;
case 'get':
responseData = await executeGetCase.call(this, credentials, itemIndex);
break;
case 'create':
responseData = await executeCreateCase.call(this, credentials, itemIndex);
break;
case 'closeCase':
responseData = await executeCloseCase.call(this, credentials, itemIndex);
break;
case 'changeOwner':
responseData = await executeChangeOwner.call(this, credentials, itemIndex);
break;
case 'checkName':
responseData = await executeCheckName.call(this, credentials, itemIndex);
break;
case 'getActivities':
responseData = await executeGetActivities.call(this, credentials, itemIndex);
break;
case 'getEndpoints':
responseData = await executeGetEndpoints.call(this, credentials, itemIndex);
break;
case 'getTasks':
responseData = await executeGetTasks.call(this, credentials, itemIndex);
break;
case 'getUsers':
responseData = await executeGetUsers.call(this, credentials, itemIndex);
break;
default:
throw new Error(`Unknown operation: ${operation}`);
}
if (operation === 'getAll' || operation === 'getActivities' || operation === 'getEndpoints' || operation === 'getTasks' || operation === 'getUsers') {
const entities = ((_a = responseData.result) === null || _a === void 0 ? void 0 : _a.entities) || [];
const paginationInfo = (0, helpers_1.extractPaginationInfo)(responseData.result);
(0, helpers_1.processApiResponseEntities)(entities, returnData, itemIndex, {
includePagination: true,
paginationData: paginationInfo,
excludeFields: ['sortables', 'filters'],
});
}
else if (operation === 'checkName') {
returnData.push({
json: responseData,
pairedItem: { item: itemIndex },
});
}
else {
const jsonData = responseData.result || responseData;
returnData.push({
json: jsonData,
pairedItem: { item: itemIndex },
});
}
}
catch (error) {
(0, helpers_1.handleExecuteError)(this, error, itemIndex, returnData);
}
}
return [returnData];
}
async function executeGetAllCases(credentials, itemIndex) {
const organizationResource = this.getNodeParameter('organizationId', itemIndex);
const additionalFields = this.getNodeParameter('additionalFields', itemIndex, {});
let organizationIds = '0';
if (organizationResource.mode === 'id') {
organizationIds = organizationResource.value;
}
else if (organizationResource.mode === 'name') {
organizationIds = await findOrganizationByName(this, credentials, organizationResource.value);
}
else if (organizationResource.mode === 'list') {
organizationIds = organizationResource.value;
}
const response = await cases_1.api.getCases(this, credentials, organizationIds, additionalFields);
(0, helpers_1.validateApiResponse)(response, 'Failed to fetch cases');
return response;
}
async function executeGetCase(credentials, itemIndex) {
var _a;
const caseResource = this.getNodeParameter('caseId', itemIndex);
const caseId = await resolveCaseResourceLocator(this, caseResource, itemIndex);
const response = await cases_1.api.getCase(this, credentials, caseId);
if (!response.success) {
const errorMessage = ((_a = response.errors) === null || _a === void 0 ? void 0 : _a.join(', ')) || 'API request failed';
throw new Error(`Failed to get case: ${errorMessage}`);
}
if (!response.result) {
throw new Error('Case not found');
}
return response;
}
async function executeCreateCase(credentials, itemIndex) {
var _a;
const caseName = this.getNodeParameter('caseName', itemIndex);
const organizationResource = this.getNodeParameter('organizationId', itemIndex);
const ownerUserResource = this.getNodeParameter('ownerUserId', itemIndex);
const visibility = this.getNodeParameter('visibility', itemIndex);
const assignedUserIdsParam = this.getNodeParameter('assignedUserIds', itemIndex, '');
let organizationId;
if (organizationResource.mode === 'id') {
organizationId = parseInt(organizationResource.value);
}
else if (organizationResource.mode === 'name') {
const orgId = await findOrganizationByName(this, credentials, organizationResource.value);
organizationId = parseInt(orgId);
}
else if (organizationResource.mode === 'list') {
organizationId = parseInt(organizationResource.value);
}
else {
throw new Error('Invalid organization selection');
}
const ownerUserId = await resolveUserResourceLocator(this, credentials, ownerUserResource, itemIndex, organizationId.toString());
let assignedUserIds = [];
if (assignedUserIdsParam.trim()) {
assignedUserIds = assignedUserIdsParam.split(',').map(id => id.trim()).filter(id => id);
}
if (visibility === 'private-to-users' && assignedUserIds.length === 0) {
throw new Error('Assigned User IDs are required when visibility is set to "private-to-users"');
}
const caseData = {
organizationId,
name: caseName,
ownerUserId,
visibility,
assignedUserIds
};
const response = await cases_1.api.createCase(this, credentials, caseData);
if (!response.success) {
const errorMessage = ((_a = response.errors) === null || _a === void 0 ? void 0 : _a.join(', ')) || 'API request failed';
throw new Error(`Failed to create case: ${errorMessage}`);
}
return response;
}
async function executeCloseCase(credentials, itemIndex) {
var _a;
const caseResource = this.getNodeParameter('caseId', itemIndex);
const caseId = await resolveCaseResourceLocator(this, caseResource, itemIndex);
const response = await cases_1.api.closeCase(this, credentials, caseId);
if (!response.success) {
const errorMessage = ((_a = response.errors) === null || _a === void 0 ? void 0 : _a.join(', ')) || 'API request failed';
throw new Error(`Failed to close case: ${errorMessage}`);
}
return response;
}
async function executeChangeOwner(credentials, itemIndex) {
var _a;
const caseResource = this.getNodeParameter('caseId', itemIndex);
const caseId = await resolveCaseResourceLocator(this, caseResource, itemIndex);
const newOwnerUserResource = this.getNodeParameter('newOwnerUserId', itemIndex);
const newOwnerUserId = await resolveUserResourceLocator(this, credentials, newOwnerUserResource, itemIndex, '0');
const response = await cases_1.api.changeOwner(this, credentials, caseId, newOwnerUserId);
if (!response.success) {
const errorMessage = ((_a = response.errors) === null || _a === void 0 ? void 0 : _a.join(', ')) || 'API request failed';
throw new Error(`Failed to change case owner: ${errorMessage}`);
}
return response;
}
async function executeCheckName(credentials, itemIndex) {
var _a;
const caseName = this.getNodeParameter('caseName', itemIndex);
const response = await cases_1.api.checkCaseName(this, credentials, caseName);
if (!response.success) {
const errorMessage = ((_a = response.errors) === null || _a === void 0 ? void 0 : _a.join(', ')) || 'API request failed';
throw new Error(`Failed to check case name: ${errorMessage}`);
}
return response;
}
async function executeGetActivities(credentials, itemIndex) {
const caseResource = this.getNodeParameter('caseId', itemIndex);
const caseId = await resolveCaseResourceLocator(this, caseResource, itemIndex);
const response = await cases_1.api.getCaseActivities(this, credentials, caseId);
(0, helpers_1.validateApiResponse)(response, 'Failed to fetch case activities');
return response;
}
async function executeGetEndpoints(credentials, itemIndex) {
const caseResource = this.getNodeParameter('caseId', itemIndex);
const caseId = await resolveCaseResourceLocator(this, caseResource, itemIndex);
const response = await cases_1.api.getCaseEndpoints(this, credentials, caseId, '0');
(0, helpers_1.validateApiResponse)(response, 'Failed to fetch case endpoints');
return response;
}
async function executeGetTasks(credentials, itemIndex) {
const caseResource = this.getNodeParameter('caseId', itemIndex);
const caseId = await resolveCaseResourceLocator(this, caseResource, itemIndex);
const response = await cases_1.api.getCaseTasksById(this, credentials, caseId, '0');
(0, helpers_1.validateApiResponse)(response, 'Failed to fetch case tasks');
return response;
}
async function executeGetUsers(credentials, itemIndex) {
const caseResource = this.getNodeParameter('caseId', itemIndex);
const caseId = await resolveCaseResourceLocator(this, caseResource, itemIndex);
const response = await cases_1.api.getCaseUsers(this, credentials, caseId, '0');
(0, helpers_1.validateApiResponse)(response, 'Failed to fetch case users');
return response;
}
//# sourceMappingURL=cases.js.map