mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-30 15:07:28 -08:00
409a9ea357
* PairedItem for N8n training * Add paired item to ftp node * Add paired item to rocketChat * Add pairedItem to pushOver * Add paired item to Matrix * Add pairedItem to theHive * Add paired item to Snowflake * Add paired item to PhilipsHue * Add pairedItem to supabase * Add paired item to Odoo * fix odoo & add paired item to grist * add pairedItem to Linkedin * add pairedItem Zulip * add pairedItem PhatomBuster * add pairedItem to TodoistV2 * Add pairedItem HomeAssistant * Add pairedItem to DropContact * Add pairedItem to Aws SES * Add pairedItem to microsoftOutlook * Add pairedItem to AwsS3 * Add pairedItem to Aws DynamoDB * 🐛 fix Dropcontact enrich operation paired item support * 🐛 fix Dropcontact insert/update operation paired items * 🐛 fix Supabase paired item support * 🐛 fix Supabase paired item support * 🐛 fix N8nTrainingCustomerDatastore paired item support * 🎨 remove unused imports * 🐛 fix MicrosoftOutlook paired item support * 🐛 fix AwsS3 paired item support --------- Co-authored-by: Marcus <marcus@n8n.io>
1977 lines
52 KiB
TypeScript
1977 lines
52 KiB
TypeScript
/* eslint-disable @typescript-eslint/dot-notation */
|
|
import type { IExecuteFunctions } from 'n8n-core';
|
|
|
|
import type {
|
|
IDataObject,
|
|
ILoadOptionsFunctions,
|
|
INodeExecutionData,
|
|
INodeParameters,
|
|
INodePropertyOptions,
|
|
INodeType,
|
|
INodeTypeDescription,
|
|
} from 'n8n-workflow';
|
|
import { NodeOperationError } from 'n8n-workflow';
|
|
|
|
import { alertFields, alertOperations } from './descriptions/AlertDescription';
|
|
|
|
import { observableFields, observableOperations } from './descriptions/ObservableDescription';
|
|
|
|
import { caseFields, caseOperations } from './descriptions/CaseDescription';
|
|
|
|
import { taskFields, taskOperations } from './descriptions/TaskDescription';
|
|
|
|
import { logFields, logOperations } from './descriptions/LogDescription';
|
|
|
|
import type { IQueryObject } from './QueryFunctions';
|
|
import { And, Between, ContainsString, Eq, Id, In, Parent } from './QueryFunctions';
|
|
|
|
import {
|
|
buildCustomFieldSearch,
|
|
mapResource,
|
|
prepareCustomFields,
|
|
prepareOptional,
|
|
prepareRangeQuery,
|
|
prepareSortQuery,
|
|
splitTags,
|
|
theHiveApiRequest,
|
|
} from './GenericFunctions';
|
|
|
|
import { set } from 'lodash';
|
|
|
|
export class TheHive implements INodeType {
|
|
description: INodeTypeDescription = {
|
|
displayName: 'TheHive',
|
|
name: 'theHive',
|
|
icon: 'file:thehive.svg',
|
|
group: ['transform'],
|
|
subtitle: '={{$parameter["operation"]}} : {{$parameter["resource"]}}',
|
|
version: 1,
|
|
description: 'Consume TheHive API',
|
|
defaults: {
|
|
name: 'TheHive',
|
|
},
|
|
inputs: ['main'],
|
|
outputs: ['main'],
|
|
credentials: [
|
|
{
|
|
name: 'theHiveApi',
|
|
required: true,
|
|
},
|
|
],
|
|
properties: [
|
|
{
|
|
displayName: 'Resource',
|
|
name: 'resource',
|
|
type: 'options',
|
|
noDataExpression: true,
|
|
required: true,
|
|
options: [
|
|
{
|
|
name: 'Alert',
|
|
value: 'alert',
|
|
},
|
|
{
|
|
name: 'Case',
|
|
value: 'case',
|
|
},
|
|
{
|
|
name: 'Log',
|
|
value: 'log',
|
|
},
|
|
{
|
|
name: 'Observable',
|
|
value: 'observable',
|
|
},
|
|
{
|
|
name: 'Task',
|
|
value: 'task',
|
|
},
|
|
],
|
|
default: 'alert',
|
|
},
|
|
// Alert
|
|
...alertOperations,
|
|
...alertFields,
|
|
// Observable
|
|
...observableOperations,
|
|
...observableFields,
|
|
// Case
|
|
...caseOperations,
|
|
...caseFields,
|
|
// Task
|
|
...taskOperations,
|
|
...taskFields,
|
|
// Log
|
|
...logOperations,
|
|
...logFields,
|
|
],
|
|
};
|
|
|
|
methods = {
|
|
loadOptions: {
|
|
async loadResponders(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
// request the analyzers from instance
|
|
const resource = mapResource(this.getNodeParameter('resource') as string);
|
|
const resourceId = this.getNodeParameter('id');
|
|
const endpoint = `/connector/cortex/responder/${resource}/${resourceId}`;
|
|
|
|
const responders = await theHiveApiRequest.call(this, 'GET', endpoint);
|
|
|
|
const returnData: INodePropertyOptions[] = [];
|
|
|
|
for (const responder of responders) {
|
|
returnData.push({
|
|
name: responder.name as string,
|
|
value: responder.id,
|
|
description: responder.description as string,
|
|
});
|
|
}
|
|
return returnData;
|
|
},
|
|
|
|
async loadAnalyzers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
// request the analyzers from instance
|
|
const dataType = this.getNodeParameter('dataType') as string;
|
|
const endpoint = `/connector/cortex/analyzer/type/${dataType}`;
|
|
const requestResult = await theHiveApiRequest.call(this, 'GET', endpoint);
|
|
const returnData: INodePropertyOptions[] = [];
|
|
|
|
for (const analyzer of requestResult) {
|
|
for (const cortexId of analyzer.cortexIds) {
|
|
returnData.push({
|
|
name: `[${cortexId}] ${analyzer.name}`,
|
|
value: `${analyzer.id as string}::${cortexId as string}`,
|
|
description: analyzer.description as string,
|
|
});
|
|
}
|
|
}
|
|
return returnData;
|
|
},
|
|
async loadCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
const version = credentials.apiVersion;
|
|
const endpoint = version === 'v1' ? '/customField' : '/list/custom_fields';
|
|
|
|
const requestResult = await theHiveApiRequest.call(this, 'GET', endpoint as string);
|
|
|
|
const returnData: INodePropertyOptions[] = [];
|
|
|
|
// Convert TheHive3 response to the same format as TheHive 4
|
|
const customFields =
|
|
version === 'v1'
|
|
? requestResult
|
|
: Object.keys(requestResult).map((key) => requestResult[key]);
|
|
|
|
for (const field of customFields) {
|
|
returnData.push({
|
|
name: `${field.name}: ${field.reference}`,
|
|
value: field.reference,
|
|
description: `${field.type}: ${field.description}`,
|
|
} as INodePropertyOptions);
|
|
}
|
|
|
|
return returnData;
|
|
},
|
|
async loadObservableOptions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
// if v1 is not used we remove 'count' option
|
|
const version = (await this.getCredentials('theHiveApi')).apiVersion;
|
|
|
|
const options = [
|
|
...(version === 'v1'
|
|
? [{ name: 'Count', value: 'count', description: 'Count observables' }]
|
|
: []),
|
|
{ name: 'Create', value: 'create', description: 'Create observable' },
|
|
{
|
|
name: 'Execute Analyzer',
|
|
value: 'executeAnalyzer',
|
|
description: 'Execute an responder on selected observable',
|
|
},
|
|
{
|
|
name: 'Execute Responder',
|
|
value: 'executeResponder',
|
|
description: 'Execute a responder on selected observable',
|
|
},
|
|
{
|
|
name: 'Get Many',
|
|
value: 'getAll',
|
|
description: 'Get all observables of a specific case',
|
|
},
|
|
{ name: 'Get', value: 'get', description: 'Get a single observable' },
|
|
{ name: 'Search', value: 'search', description: 'Search observables' },
|
|
{ name: 'Update', value: 'update', description: 'Update observable' },
|
|
];
|
|
return options;
|
|
},
|
|
async loadObservableTypes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
const version = (await this.getCredentials('theHiveApi')).apiVersion;
|
|
const endpoint =
|
|
version === 'v1' ? '/observable/type?range=all' : '/list/list_artifactDataType';
|
|
|
|
const dataTypes = await theHiveApiRequest.call(this, 'GET', endpoint as string);
|
|
|
|
let returnData: INodePropertyOptions[] = [];
|
|
|
|
if (version === 'v1') {
|
|
returnData = dataTypes.map((dataType: IDataObject) => {
|
|
return {
|
|
name: dataType.name as string,
|
|
value: dataType.name as string,
|
|
};
|
|
});
|
|
} else {
|
|
returnData = Object.keys(dataTypes).map((key) => {
|
|
const dataType = dataTypes[key] as string;
|
|
|
|
return {
|
|
name: dataType,
|
|
value: dataType,
|
|
};
|
|
});
|
|
}
|
|
|
|
// Sort the array by option name
|
|
returnData.sort((a, b) => {
|
|
if (a.name < b.name) {
|
|
return -1;
|
|
}
|
|
if (a.name > b.name) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
});
|
|
|
|
return returnData;
|
|
},
|
|
async loadTaskOptions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
const version = credentials.apiVersion;
|
|
const options = [
|
|
...(version === 'v1'
|
|
? [{ name: 'Count', value: 'count', description: 'Count tasks' }]
|
|
: []),
|
|
{ name: 'Create', value: 'create', description: 'Create a task' },
|
|
{
|
|
name: 'Execute Responder',
|
|
value: 'executeResponder',
|
|
description: 'Execute a responder on the specified task',
|
|
},
|
|
{ name: 'Get Many', value: 'getAll', description: 'Get all asks of a specific case' },
|
|
{ name: 'Get', value: 'get', description: 'Get a single task' },
|
|
{ name: 'Search', value: 'search', description: 'Search tasks' },
|
|
{ name: 'Update', value: 'update', description: 'Update a task' },
|
|
];
|
|
return options;
|
|
},
|
|
async loadAlertOptions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
const version = credentials.apiVersion;
|
|
const options = [
|
|
...(version === 'v1'
|
|
? [{ name: 'Count', value: 'count', description: 'Count alerts' }]
|
|
: []),
|
|
{ name: 'Create', value: 'create', description: 'Create alert' },
|
|
{
|
|
name: 'Execute Responder',
|
|
value: 'executeResponder',
|
|
description: 'Execute a responder on the specified alert',
|
|
},
|
|
{ name: 'Get', value: 'get', description: 'Get an alert' },
|
|
{ name: 'Get Many', value: 'getAll', description: 'Get all alerts' },
|
|
{ name: 'Mark as Read', value: 'markAsRead', description: 'Mark the alert as read' },
|
|
{
|
|
name: 'Mark as Unread',
|
|
value: 'markAsUnread',
|
|
description: 'Mark the alert as unread',
|
|
},
|
|
{ name: 'Merge', value: 'merge', description: 'Merge alert into an existing case' },
|
|
{ name: 'Promote', value: 'promote', description: 'Promote an alert into a case' },
|
|
{ name: 'Update', value: 'update', description: 'Update alert' },
|
|
];
|
|
return options;
|
|
},
|
|
async loadCaseOptions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
const version = credentials.apiVersion;
|
|
const options = [
|
|
...(version === 'v1'
|
|
? [{ name: 'Count', value: 'count', description: 'Count a case' }]
|
|
: []),
|
|
{ name: 'Create', value: 'create', description: 'Create a case' },
|
|
{
|
|
name: 'Execute Responder',
|
|
value: 'executeResponder',
|
|
description: 'Execute a responder on the specified case',
|
|
},
|
|
{ name: 'Get Many', value: 'getAll', description: 'Get all cases' },
|
|
{ name: 'Get', value: 'get', description: 'Get a single case' },
|
|
{ name: 'Update', value: 'update', description: 'Update a case' },
|
|
];
|
|
return options;
|
|
},
|
|
},
|
|
};
|
|
|
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
|
const items = this.getInputData();
|
|
const returnData: INodeExecutionData[] = [];
|
|
const length = items.length;
|
|
const qs: IDataObject = {};
|
|
let responseData;
|
|
const resource = this.getNodeParameter('resource', 0);
|
|
const operation = this.getNodeParameter('operation', 0);
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
try {
|
|
if (resource === 'alert') {
|
|
if (operation === 'count') {
|
|
const filters = this.getNodeParameter('filters', i, {}) as INodeParameters;
|
|
const countQueryAttributs: any = prepareOptional(filters);
|
|
|
|
const _countSearchQuery: IQueryObject = And();
|
|
|
|
if ('customFieldsUi' in filters) {
|
|
const customFields = (await prepareCustomFields.call(this, filters)) as IDataObject;
|
|
const searchQueries = buildCustomFieldSearch(customFields);
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(...searchQueries);
|
|
}
|
|
|
|
for (const key of Object.keys(countQueryAttributs)) {
|
|
if (key === 'tags') {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
In(key, countQueryAttributs[key] as string[]),
|
|
);
|
|
} else if (key === 'description' || key === 'title') {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
ContainsString(key, countQueryAttributs[key] as string),
|
|
);
|
|
} else {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
Eq(key, countQueryAttributs[key] as string),
|
|
);
|
|
}
|
|
}
|
|
|
|
const body = {
|
|
query: [
|
|
{
|
|
_name: 'listAlert',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: _countSearchQuery['_and'],
|
|
},
|
|
],
|
|
};
|
|
|
|
body['query'].push({
|
|
_name: 'count',
|
|
});
|
|
|
|
qs.name = 'count-Alert';
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
|
|
responseData = { count: responseData };
|
|
}
|
|
|
|
if (operation === 'create') {
|
|
const additionalFields = this.getNodeParameter(
|
|
'additionalFields',
|
|
i,
|
|
) as INodeParameters;
|
|
const jsonParameters = this.getNodeParameter('jsonParameters', i);
|
|
|
|
const customFields = await prepareCustomFields.call(
|
|
this,
|
|
additionalFields,
|
|
jsonParameters,
|
|
);
|
|
const body: IDataObject = {
|
|
title: this.getNodeParameter('title', i),
|
|
description: this.getNodeParameter('description', i),
|
|
severity: this.getNodeParameter('severity', i),
|
|
date: Date.parse(this.getNodeParameter('date', i) as string),
|
|
tags: splitTags(this.getNodeParameter('tags', i) as string),
|
|
tlp: this.getNodeParameter('tlp', i),
|
|
status: this.getNodeParameter('status', i),
|
|
type: this.getNodeParameter('type', i),
|
|
source: this.getNodeParameter('source', i),
|
|
sourceRef: this.getNodeParameter('sourceRef', i),
|
|
follow: this.getNodeParameter('follow', i, true),
|
|
...prepareOptional(additionalFields),
|
|
};
|
|
|
|
if (customFields) {
|
|
Object.keys(customFields).forEach((key) => {
|
|
set(body, key, customFields[key]);
|
|
});
|
|
}
|
|
|
|
const artifactUi = this.getNodeParameter('artifactUi', i) as IDataObject;
|
|
|
|
if (artifactUi) {
|
|
const artifactValues = artifactUi.artifactValues as IDataObject[];
|
|
|
|
if (artifactValues) {
|
|
const artifactData = [];
|
|
|
|
for (const artifactvalue of artifactValues) {
|
|
const element: IDataObject = {};
|
|
|
|
element.message = artifactvalue.message as string;
|
|
|
|
element.tags = (artifactvalue.tags as string).split(',');
|
|
|
|
element.dataType = artifactvalue.dataType as string;
|
|
|
|
element.data = artifactvalue.data as string;
|
|
|
|
if (artifactvalue.dataType === 'file') {
|
|
const item = items[i];
|
|
|
|
if (item.binary === undefined) {
|
|
throw new NodeOperationError(
|
|
this.getNode(),
|
|
'No binary data exists on item!',
|
|
{ itemIndex: i },
|
|
);
|
|
}
|
|
|
|
const binaryPropertyName = artifactvalue.binaryProperty as string;
|
|
|
|
if (item.binary[binaryPropertyName] === undefined) {
|
|
throw new NodeOperationError(
|
|
this.getNode(),
|
|
`No binary data property '${binaryPropertyName}' does not exists on item!`,
|
|
{ itemIndex: i },
|
|
);
|
|
}
|
|
|
|
const binaryData = item.binary[binaryPropertyName];
|
|
|
|
element.data = `${binaryData.fileName};${binaryData.mimeType};${binaryData.data}`;
|
|
}
|
|
|
|
artifactData.push(element);
|
|
}
|
|
body.artifacts = artifactData;
|
|
}
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'POST', '/alert' as string, body);
|
|
}
|
|
|
|
/*
|
|
Execute responder feature differs from Cortex execute responder
|
|
if it doesn't interfere with n8n standards then we should keep it
|
|
*/
|
|
|
|
if (operation === 'executeResponder') {
|
|
const alertId = this.getNodeParameter('id', i);
|
|
const responderId = this.getNodeParameter('responder', i) as string;
|
|
let body: IDataObject;
|
|
let response;
|
|
responseData = [];
|
|
body = {
|
|
responderId,
|
|
objectId: alertId,
|
|
objectType: 'alert',
|
|
};
|
|
response = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
'/connector/cortex/action' as string,
|
|
body,
|
|
);
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listAction',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: [
|
|
{
|
|
_field: 'cortexId',
|
|
_value: response.cortexId,
|
|
},
|
|
{
|
|
_field: 'objectId',
|
|
_value: response.objectId,
|
|
},
|
|
{
|
|
_field: 'startDate',
|
|
_value: response.startDate,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
qs.name = 'log-actions';
|
|
do {
|
|
response = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
} while (response.status === 'Waiting' || response.status === 'InProgress');
|
|
|
|
responseData = response;
|
|
}
|
|
|
|
if (operation === 'get') {
|
|
const alertId = this.getNodeParameter('id', i) as string;
|
|
const includeSimilar = this.getNodeParameter(
|
|
'options.includeSimilar',
|
|
i,
|
|
false,
|
|
) as boolean;
|
|
|
|
if (includeSimilar) {
|
|
qs.similarity = true;
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'GET', `/alert/${alertId}`, {}, qs);
|
|
}
|
|
if (operation === 'getAll') {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
const filters = this.getNodeParameter('filters', i, {}) as INodeParameters;
|
|
const queryAttributs: any = prepareOptional(filters);
|
|
const options = this.getNodeParameter('options', i);
|
|
|
|
const _searchQuery: IQueryObject = And();
|
|
|
|
if ('customFieldsUi' in filters) {
|
|
const customFields = (await prepareCustomFields.call(this, filters)) as IDataObject;
|
|
const searchQueries = buildCustomFieldSearch(customFields);
|
|
(_searchQuery['_and'] as IQueryObject[]).push(...searchQueries);
|
|
}
|
|
|
|
for (const key of Object.keys(queryAttributs)) {
|
|
if (key === 'tags') {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
In(key, queryAttributs[key] as string[]),
|
|
);
|
|
} else if (key === 'description' || key === 'title') {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
ContainsString(key, queryAttributs[key] as string),
|
|
);
|
|
} else {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
Eq(key, queryAttributs[key] as string),
|
|
);
|
|
}
|
|
}
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
let limit = undefined;
|
|
|
|
if (!returnAll) {
|
|
limit = this.getNodeParameter('limit', i);
|
|
}
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listAlert',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: _searchQuery['_and'],
|
|
},
|
|
],
|
|
};
|
|
|
|
//@ts-ignore
|
|
prepareSortQuery(options.sort, body);
|
|
|
|
if (limit !== undefined) {
|
|
//@ts-ignore
|
|
prepareRangeQuery(`0-${limit}`, body);
|
|
}
|
|
|
|
qs.name = 'alerts';
|
|
} else {
|
|
method = 'POST';
|
|
|
|
endpoint = '/alert/_search';
|
|
|
|
if (limit !== undefined) {
|
|
qs.range = `0-${limit}`;
|
|
}
|
|
|
|
body.query = _searchQuery;
|
|
|
|
Object.assign(qs, prepareOptional(options));
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'markAsRead') {
|
|
const alertId = this.getNodeParameter('id', i) as string;
|
|
|
|
responseData = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
`/alert/${alertId}/markAsRead`,
|
|
);
|
|
}
|
|
|
|
if (operation === 'markAsUnread') {
|
|
const alertId = this.getNodeParameter('id', i) as string;
|
|
|
|
responseData = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
`/alert/${alertId}/markAsUnread`,
|
|
);
|
|
}
|
|
|
|
if (operation === 'merge') {
|
|
const alertId = this.getNodeParameter('id', i) as string;
|
|
|
|
const caseId = this.getNodeParameter('caseId', i) as string;
|
|
|
|
responseData = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
`/alert/${alertId}/merge/${caseId}`,
|
|
{},
|
|
);
|
|
}
|
|
|
|
if (operation === 'promote') {
|
|
const alertId = this.getNodeParameter('id', i) as string;
|
|
|
|
const additionalFields = this.getNodeParameter('additionalFields', i);
|
|
|
|
const body: IDataObject = {};
|
|
|
|
Object.assign(body, additionalFields);
|
|
|
|
responseData = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
`/alert/${alertId}/createCase`,
|
|
body,
|
|
);
|
|
}
|
|
|
|
if (operation === 'update') {
|
|
const alertId = this.getNodeParameter('id', i) as string;
|
|
const jsonParameters = this.getNodeParameter('jsonParameters', i);
|
|
|
|
const updateFields = this.getNodeParameter('updateFields', i);
|
|
const customFields = await prepareCustomFields.call(this, updateFields, jsonParameters);
|
|
|
|
const artifactUi = updateFields.artifactUi as IDataObject;
|
|
|
|
delete updateFields.artifactUi;
|
|
|
|
const body: IDataObject = {
|
|
...customFields,
|
|
};
|
|
|
|
Object.assign(body, updateFields);
|
|
|
|
if (artifactUi) {
|
|
const artifactValues = artifactUi.artifactValues as IDataObject[];
|
|
|
|
if (artifactValues) {
|
|
const artifactData = [];
|
|
|
|
for (const artifactvalue of artifactValues) {
|
|
const element: IDataObject = {};
|
|
|
|
element.message = artifactvalue.message as string;
|
|
|
|
element.tags = (artifactvalue.tags as string).split(',');
|
|
|
|
element.dataType = artifactvalue.dataType as string;
|
|
|
|
element.data = artifactvalue.data as string;
|
|
|
|
if (artifactvalue.dataType === 'file') {
|
|
const item = items[i];
|
|
|
|
if (item.binary === undefined) {
|
|
throw new NodeOperationError(
|
|
this.getNode(),
|
|
'No binary data exists on item!',
|
|
{ itemIndex: i },
|
|
);
|
|
}
|
|
|
|
const binaryPropertyName = artifactvalue.binaryProperty as string;
|
|
|
|
if (item.binary[binaryPropertyName] === undefined) {
|
|
throw new NodeOperationError(
|
|
this.getNode(),
|
|
`No binary data property '${binaryPropertyName}' does not exists on item!`,
|
|
{ itemIndex: i },
|
|
);
|
|
}
|
|
|
|
const binaryData = item.binary[binaryPropertyName];
|
|
|
|
element.data = `${binaryData.fileName};${binaryData.mimeType};${binaryData.data}`;
|
|
}
|
|
|
|
artifactData.push(element);
|
|
}
|
|
body.artifacts = artifactData;
|
|
}
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'PATCH', `/alert/${alertId}`, body);
|
|
}
|
|
}
|
|
|
|
if (resource === 'observable') {
|
|
if (operation === 'count') {
|
|
const countQueryAttributs: any = prepareOptional(
|
|
this.getNodeParameter('filters', i, {}) as INodeParameters,
|
|
);
|
|
const _countSearchQuery: IQueryObject = And();
|
|
|
|
for (const key of Object.keys(countQueryAttributs)) {
|
|
if (key === 'dataType' || key === 'tags') {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
In(key, countQueryAttributs[key] as string[]),
|
|
);
|
|
} else if (key === 'description' || key === 'keywork' || key === 'message') {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
ContainsString(key, countQueryAttributs[key] as string),
|
|
);
|
|
} else if (key === 'range') {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
Between(
|
|
'startDate',
|
|
countQueryAttributs['range']['dateRange']['fromDate'],
|
|
countQueryAttributs['range']['dateRange']['toDate'],
|
|
),
|
|
);
|
|
} else {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
Eq(key, countQueryAttributs[key] as string),
|
|
);
|
|
}
|
|
}
|
|
|
|
const body = {
|
|
query: [
|
|
{
|
|
_name: 'listObservable',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: _countSearchQuery['_and'],
|
|
},
|
|
],
|
|
};
|
|
|
|
body['query'].push({
|
|
_name: 'count',
|
|
});
|
|
|
|
qs.name = 'count-observables';
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
|
|
responseData = { count: responseData };
|
|
}
|
|
|
|
if (operation === 'executeAnalyzer') {
|
|
const observableId = this.getNodeParameter('id', i);
|
|
const analyzers = (this.getNodeParameter('analyzers', i) as string[]).map(
|
|
(analyzer) => {
|
|
const parts = analyzer.split('::');
|
|
return {
|
|
analyzerId: parts[0],
|
|
cortexId: parts[1],
|
|
};
|
|
},
|
|
);
|
|
let response: any;
|
|
let body: IDataObject;
|
|
responseData = [];
|
|
for (const analyzer of analyzers) {
|
|
body = {
|
|
...analyzer,
|
|
artifactId: observableId,
|
|
};
|
|
// execute the analyzer
|
|
response = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
'/connector/cortex/job' as string,
|
|
body,
|
|
qs,
|
|
);
|
|
const jobId = response.id;
|
|
qs.name = 'observable-jobs';
|
|
// query the job result (including the report)
|
|
do {
|
|
responseData = await theHiveApiRequest.call(
|
|
this,
|
|
'GET',
|
|
`/connector/cortex/job/${jobId}`,
|
|
body,
|
|
qs,
|
|
);
|
|
} while (responseData.status === 'Waiting' || responseData.status === 'InProgress');
|
|
}
|
|
}
|
|
|
|
if (operation === 'executeResponder') {
|
|
const observableId = this.getNodeParameter('id', i);
|
|
const responderId = this.getNodeParameter('responder', i) as string;
|
|
let body: IDataObject;
|
|
let response;
|
|
responseData = [];
|
|
body = {
|
|
responderId,
|
|
objectId: observableId,
|
|
objectType: 'case_artifact',
|
|
};
|
|
response = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
'/connector/cortex/action' as string,
|
|
body,
|
|
);
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listAction',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: [
|
|
{
|
|
_field: 'cortexId',
|
|
_value: response.cortexId,
|
|
},
|
|
{
|
|
_field: 'objectId',
|
|
_value: response.objectId,
|
|
},
|
|
{
|
|
_field: 'startDate',
|
|
_value: response.startDate,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
qs.name = 'log-actions';
|
|
do {
|
|
response = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
} while (response.status === 'Waiting' || response.status === 'InProgress');
|
|
|
|
responseData = response;
|
|
}
|
|
|
|
if (operation === 'create') {
|
|
const caseId = this.getNodeParameter('caseId', i);
|
|
|
|
let body: IDataObject = {
|
|
dataType: this.getNodeParameter('dataType', i) as string,
|
|
message: this.getNodeParameter('message', i) as string,
|
|
startDate: Date.parse(this.getNodeParameter('startDate', i) as string),
|
|
tlp: this.getNodeParameter('tlp', i) as number,
|
|
ioc: this.getNodeParameter('ioc', i) as boolean,
|
|
sighted: this.getNodeParameter('sighted', i) as boolean,
|
|
status: this.getNodeParameter('status', i) as string,
|
|
...prepareOptional(this.getNodeParameter('options', i, {}) as INodeParameters),
|
|
};
|
|
|
|
let options: IDataObject = {};
|
|
|
|
if (body.dataType === 'file') {
|
|
const item = items[i];
|
|
|
|
if (item.binary === undefined) {
|
|
throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', {
|
|
itemIndex: i,
|
|
});
|
|
}
|
|
|
|
const binaryPropertyName = this.getNodeParameter('binaryProperty', i);
|
|
|
|
if (item.binary[binaryPropertyName] === undefined) {
|
|
throw new NodeOperationError(
|
|
this.getNode(),
|
|
`No binary data property '${binaryPropertyName}' does not exists on item!`,
|
|
{ itemIndex: i },
|
|
);
|
|
}
|
|
|
|
const binaryData = item.binary[binaryPropertyName];
|
|
const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
|
|
options = {
|
|
formData: {
|
|
attachment: {
|
|
value: dataBuffer,
|
|
options: {
|
|
contentType: binaryData.mimeType,
|
|
filename: binaryData.fileName,
|
|
},
|
|
},
|
|
_json: JSON.stringify(body),
|
|
},
|
|
};
|
|
body = {};
|
|
} else {
|
|
body.data = this.getNodeParameter('data', i) as string;
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
`/case/${caseId}/artifact`,
|
|
body,
|
|
qs,
|
|
'',
|
|
options,
|
|
);
|
|
}
|
|
|
|
if (operation === 'get') {
|
|
const observableId = this.getNodeParameter('id', i) as string;
|
|
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'getObservable',
|
|
idOrName: observableId,
|
|
},
|
|
],
|
|
};
|
|
|
|
qs.name = `get-observable-${observableId}`;
|
|
} else {
|
|
method = 'GET';
|
|
|
|
endpoint = `/case/artifact/${observableId}`;
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'getAll') {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
const options = this.getNodeParameter('options', i);
|
|
|
|
const caseId = this.getNodeParameter('caseId', i);
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
let limit = undefined;
|
|
|
|
if (!returnAll) {
|
|
limit = this.getNodeParameter('limit', i);
|
|
}
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'getCase',
|
|
idOrName: caseId,
|
|
},
|
|
{
|
|
_name: 'observables',
|
|
},
|
|
],
|
|
};
|
|
|
|
//@ts-ignore
|
|
prepareSortQuery(options.sort, body);
|
|
|
|
if (limit !== undefined) {
|
|
//@ts-ignore
|
|
prepareRangeQuery(`0-${limit}`, body);
|
|
}
|
|
|
|
qs.name = 'observables';
|
|
} else {
|
|
method = 'POST';
|
|
|
|
endpoint = '/case/artifact/_search';
|
|
|
|
if (limit !== undefined) {
|
|
qs.range = `0-${limit}`;
|
|
}
|
|
|
|
body.query = Parent('case', Id(caseId as string));
|
|
|
|
Object.assign(qs, prepareOptional(options));
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'search') {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
const queryAttributs: any = prepareOptional(
|
|
this.getNodeParameter('filters', i, {}) as INodeParameters,
|
|
);
|
|
|
|
const _searchQuery: IQueryObject = And();
|
|
|
|
const options = this.getNodeParameter('options', i);
|
|
|
|
for (const key of Object.keys(queryAttributs)) {
|
|
if (key === 'dataType' || key === 'tags') {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
In(key, queryAttributs[key] as string[]),
|
|
);
|
|
} else if (key === 'description' || key === 'keywork' || key === 'message') {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
ContainsString(key, queryAttributs[key] as string),
|
|
);
|
|
} else if (key === 'range') {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
Between(
|
|
'startDate',
|
|
queryAttributs['range']['dateRange']['fromDate'],
|
|
queryAttributs['range']['dateRange']['toDate'],
|
|
),
|
|
);
|
|
} else {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
Eq(key, queryAttributs[key] as string),
|
|
);
|
|
}
|
|
}
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
let limit = undefined;
|
|
|
|
if (!returnAll) {
|
|
limit = this.getNodeParameter('limit', i);
|
|
}
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listObservable',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: _searchQuery['_and'],
|
|
},
|
|
],
|
|
};
|
|
|
|
//@ts-ignore
|
|
prepareSortQuery(options.sort, body);
|
|
|
|
if (limit !== undefined) {
|
|
//@ts-ignore
|
|
prepareRangeQuery(`0-${limit}`, body);
|
|
}
|
|
|
|
qs.name = 'observables';
|
|
} else {
|
|
method = 'POST';
|
|
|
|
endpoint = '/case/artifact/_search';
|
|
|
|
if (limit !== undefined) {
|
|
qs.range = `0-${limit}`;
|
|
}
|
|
|
|
body.query = _searchQuery;
|
|
|
|
Object.assign(qs, prepareOptional(options));
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'update') {
|
|
const id = this.getNodeParameter('id', i) as string;
|
|
|
|
const body: IDataObject = {
|
|
...prepareOptional(this.getNodeParameter('updateFields', i, {}) as INodeParameters),
|
|
};
|
|
|
|
responseData = await theHiveApiRequest.call(
|
|
this,
|
|
'PATCH',
|
|
`/case/artifact/${id}`,
|
|
body,
|
|
qs,
|
|
);
|
|
|
|
responseData = { success: true };
|
|
}
|
|
}
|
|
|
|
if (resource === 'case') {
|
|
if (operation === 'count') {
|
|
const filters = this.getNodeParameter('filters', i, {}) as INodeParameters;
|
|
const countQueryAttributs: any = prepareOptional(filters);
|
|
|
|
const _countSearchQuery: IQueryObject = And();
|
|
|
|
if ('customFieldsUi' in filters) {
|
|
const customFields = (await prepareCustomFields.call(this, filters)) as IDataObject;
|
|
const searchQueries = buildCustomFieldSearch(customFields);
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(...searchQueries);
|
|
}
|
|
|
|
for (const key of Object.keys(countQueryAttributs)) {
|
|
if (key === 'tags') {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
In(key, countQueryAttributs[key] as string[]),
|
|
);
|
|
} else if (key === 'description' || key === 'summary' || key === 'title') {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
ContainsString(key, countQueryAttributs[key] as string),
|
|
);
|
|
} else {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
Eq(key, countQueryAttributs[key] as string),
|
|
);
|
|
}
|
|
}
|
|
|
|
const body = {
|
|
query: [
|
|
{
|
|
_name: 'listCase',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: _countSearchQuery['_and'],
|
|
},
|
|
],
|
|
};
|
|
|
|
body['query'].push({
|
|
_name: 'count',
|
|
});
|
|
|
|
qs.name = 'count-cases';
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
|
|
responseData = { count: responseData };
|
|
}
|
|
|
|
if (operation === 'executeResponder') {
|
|
const caseId = this.getNodeParameter('id', i);
|
|
const responderId = this.getNodeParameter('responder', i) as string;
|
|
let body: IDataObject;
|
|
let response;
|
|
responseData = [];
|
|
body = {
|
|
responderId,
|
|
objectId: caseId,
|
|
objectType: 'case',
|
|
};
|
|
response = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
'/connector/cortex/action' as string,
|
|
body,
|
|
);
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listAction',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: [
|
|
{
|
|
_field: 'cortexId',
|
|
_value: response.cortexId,
|
|
},
|
|
{
|
|
_field: 'objectId',
|
|
_value: response.objectId,
|
|
},
|
|
{
|
|
_field: 'startDate',
|
|
_value: response.startDate,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
qs.name = 'log-actions';
|
|
do {
|
|
response = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
} while (response.status === 'Waiting' || response.status === 'InProgress');
|
|
|
|
responseData = response;
|
|
}
|
|
|
|
if (operation === 'create') {
|
|
const options = this.getNodeParameter('options', i, {}) as INodeParameters;
|
|
const jsonParameters = this.getNodeParameter('jsonParameters', i);
|
|
const customFields = await prepareCustomFields.call(this, options, jsonParameters);
|
|
|
|
const body: IDataObject = {
|
|
title: this.getNodeParameter('title', i),
|
|
description: this.getNodeParameter('description', i),
|
|
severity: this.getNodeParameter('severity', i),
|
|
startDate: Date.parse(this.getNodeParameter('startDate', i) as string),
|
|
owner: this.getNodeParameter('owner', i),
|
|
flag: this.getNodeParameter('flag', i),
|
|
tlp: this.getNodeParameter('tlp', i),
|
|
tags: splitTags(this.getNodeParameter('tags', i) as string),
|
|
...prepareOptional(options),
|
|
};
|
|
|
|
if (customFields) {
|
|
Object.keys(customFields).forEach((key) => {
|
|
set(body, key, customFields[key]);
|
|
});
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'POST', '/case' as string, body);
|
|
}
|
|
|
|
if (operation === 'get') {
|
|
const caseId = this.getNodeParameter('id', i) as string;
|
|
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'getCase',
|
|
idOrName: caseId,
|
|
},
|
|
],
|
|
};
|
|
|
|
qs.name = `get-case-${caseId}`;
|
|
} else {
|
|
method = 'GET';
|
|
|
|
endpoint = `/case/${caseId}`;
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'getAll') {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
const filters = this.getNodeParameter('filters', i, {}) as INodeParameters;
|
|
const queryAttributs: any = prepareOptional(filters);
|
|
|
|
const _searchQuery: IQueryObject = And();
|
|
|
|
const options = this.getNodeParameter('options', i);
|
|
|
|
if ('customFieldsUi' in filters) {
|
|
const customFields = (await prepareCustomFields.call(this, filters)) as IDataObject;
|
|
const searchQueries = buildCustomFieldSearch(customFields);
|
|
(_searchQuery['_and'] as IQueryObject[]).push(...searchQueries);
|
|
}
|
|
|
|
for (const key of Object.keys(queryAttributs)) {
|
|
if (key === 'tags') {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
In(key, queryAttributs[key] as string[]),
|
|
);
|
|
} else if (key === 'description' || key === 'summary' || key === 'title') {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
ContainsString(key, queryAttributs[key] as string),
|
|
);
|
|
} else {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
Eq(key, queryAttributs[key] as string),
|
|
);
|
|
}
|
|
}
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
let limit = undefined;
|
|
|
|
if (!returnAll) {
|
|
limit = this.getNodeParameter('limit', i);
|
|
}
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listCase',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: _searchQuery['_and'],
|
|
},
|
|
],
|
|
};
|
|
|
|
//@ts-ignore
|
|
prepareSortQuery(options.sort, body);
|
|
|
|
if (limit !== undefined) {
|
|
//@ts-ignore
|
|
prepareRangeQuery(`0-${limit}`, body);
|
|
}
|
|
|
|
qs.name = 'cases';
|
|
} else {
|
|
method = 'POST';
|
|
|
|
endpoint = '/case/_search';
|
|
|
|
if (limit !== undefined) {
|
|
qs.range = `0-${limit}`;
|
|
}
|
|
|
|
body.query = _searchQuery;
|
|
|
|
Object.assign(qs, prepareOptional(options));
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'update') {
|
|
const id = this.getNodeParameter('id', i) as string;
|
|
const updateFields = this.getNodeParameter('updateFields', i, {}) as INodeParameters;
|
|
const jsonParameters = this.getNodeParameter('jsonParameters', i);
|
|
|
|
const customFields = await prepareCustomFields.call(this, updateFields, jsonParameters);
|
|
|
|
const body: IDataObject = {
|
|
...customFields,
|
|
...prepareOptional(updateFields),
|
|
};
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'PATCH', `/case/${id}`, body);
|
|
}
|
|
}
|
|
|
|
if (resource === 'task') {
|
|
if (operation === 'count') {
|
|
const countQueryAttributs: any = prepareOptional(
|
|
this.getNodeParameter('filters', i, {}) as INodeParameters,
|
|
);
|
|
|
|
const _countSearchQuery: IQueryObject = And();
|
|
|
|
for (const key of Object.keys(countQueryAttributs)) {
|
|
if (key === 'title' || key === 'description') {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
ContainsString(key, countQueryAttributs[key] as string),
|
|
);
|
|
} else {
|
|
(_countSearchQuery['_and'] as IQueryObject[]).push(
|
|
Eq(key, countQueryAttributs[key] as string),
|
|
);
|
|
}
|
|
}
|
|
|
|
const body = {
|
|
query: [
|
|
{
|
|
_name: 'listTask',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: _countSearchQuery['_and'],
|
|
},
|
|
],
|
|
};
|
|
|
|
body['query'].push({
|
|
_name: 'count',
|
|
});
|
|
|
|
qs.name = 'count-tasks';
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
|
|
responseData = { count: responseData };
|
|
}
|
|
|
|
if (operation === 'create') {
|
|
const caseId = this.getNodeParameter('caseId', i) as string;
|
|
|
|
const body: IDataObject = {
|
|
title: this.getNodeParameter('title', i) as string,
|
|
status: this.getNodeParameter('status', i) as string,
|
|
flag: this.getNodeParameter('flag', i),
|
|
...prepareOptional(this.getNodeParameter('options', i, {}) as INodeParameters),
|
|
};
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'POST', `/case/${caseId}/task`, body);
|
|
}
|
|
|
|
if (operation === 'executeResponder') {
|
|
const taskId = this.getNodeParameter('id', i);
|
|
const responderId = this.getNodeParameter('responder', i) as string;
|
|
let body: IDataObject;
|
|
let response;
|
|
responseData = [];
|
|
body = {
|
|
responderId,
|
|
objectId: taskId,
|
|
objectType: 'case_task',
|
|
};
|
|
response = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
'/connector/cortex/action' as string,
|
|
body,
|
|
);
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listAction',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: [
|
|
{
|
|
_field: 'cortexId',
|
|
_value: response.cortexId,
|
|
},
|
|
{
|
|
_field: 'objectId',
|
|
_value: response.objectId,
|
|
},
|
|
{
|
|
_field: 'startDate',
|
|
_value: response.startDate,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
qs.name = 'task-actions';
|
|
do {
|
|
response = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
} while (response.status === 'Waiting' || response.status === 'InProgress');
|
|
|
|
responseData = response;
|
|
}
|
|
|
|
if (operation === 'get') {
|
|
const taskId = this.getNodeParameter('id', i) as string;
|
|
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'getTask',
|
|
idOrName: taskId,
|
|
},
|
|
],
|
|
};
|
|
|
|
qs.name = `get-task-${taskId}`;
|
|
} else {
|
|
method = 'GET';
|
|
|
|
endpoint = `/case/task/${taskId}`;
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'getAll') {
|
|
// get all require a case id (it retursn all tasks for a specific case)
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
const caseId = this.getNodeParameter('caseId', i) as string;
|
|
|
|
const options = this.getNodeParameter('options', i);
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
let limit = undefined;
|
|
|
|
if (!returnAll) {
|
|
limit = this.getNodeParameter('limit', i);
|
|
}
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'getCase',
|
|
idOrName: caseId,
|
|
},
|
|
{
|
|
_name: 'tasks',
|
|
},
|
|
],
|
|
};
|
|
|
|
//@ts-ignore
|
|
prepareSortQuery(options.sort, body);
|
|
|
|
if (limit !== undefined) {
|
|
//@ts-ignore
|
|
prepareRangeQuery(`0-${limit}`, body);
|
|
}
|
|
|
|
qs.name = 'case-tasks';
|
|
} else {
|
|
method = 'POST';
|
|
|
|
endpoint = '/case/task/_search';
|
|
|
|
if (limit !== undefined) {
|
|
qs.range = `0-${limit}`;
|
|
}
|
|
|
|
body.query = And(Parent('case', Id(caseId)));
|
|
|
|
Object.assign(qs, prepareOptional(options));
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'search') {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
const queryAttributs: any = prepareOptional(
|
|
this.getNodeParameter('filters', i, {}) as INodeParameters,
|
|
);
|
|
|
|
const _searchQuery: IQueryObject = And();
|
|
|
|
const options = this.getNodeParameter('options', i);
|
|
|
|
for (const key of Object.keys(queryAttributs)) {
|
|
if (key === 'title' || key === 'description') {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
ContainsString(key, queryAttributs[key] as string),
|
|
);
|
|
} else {
|
|
(_searchQuery['_and'] as IQueryObject[]).push(
|
|
Eq(key, queryAttributs[key] as string),
|
|
);
|
|
}
|
|
}
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
let limit = undefined;
|
|
|
|
if (!returnAll) {
|
|
limit = this.getNodeParameter('limit', i);
|
|
}
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listTask',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: _searchQuery['_and'],
|
|
},
|
|
],
|
|
};
|
|
|
|
//@ts-ignore
|
|
prepareSortQuery(options.sort, body);
|
|
|
|
if (limit !== undefined) {
|
|
//@ts-ignore
|
|
prepareRangeQuery(`0-${limit}`, body);
|
|
}
|
|
|
|
qs.name = 'tasks';
|
|
} else {
|
|
method = 'POST';
|
|
|
|
endpoint = '/case/task/_search';
|
|
|
|
if (limit !== undefined) {
|
|
qs.range = `0-${limit}`;
|
|
}
|
|
|
|
body.query = _searchQuery;
|
|
|
|
Object.assign(qs, prepareOptional(options));
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'update') {
|
|
const id = this.getNodeParameter('id', i) as string;
|
|
|
|
const body: IDataObject = {
|
|
...prepareOptional(this.getNodeParameter('updateFields', i, {}) as INodeParameters),
|
|
};
|
|
|
|
responseData = await theHiveApiRequest.call(this, 'PATCH', `/case/task/${id}`, body);
|
|
}
|
|
}
|
|
|
|
if (resource === 'log') {
|
|
if (operation === 'create') {
|
|
const taskId = this.getNodeParameter('taskId', i) as string;
|
|
|
|
let body: IDataObject = {
|
|
message: this.getNodeParameter('message', i),
|
|
startDate: Date.parse(this.getNodeParameter('startDate', i) as string),
|
|
status: this.getNodeParameter('status', i),
|
|
};
|
|
const optionals = this.getNodeParameter('options', i);
|
|
|
|
let options: IDataObject = {};
|
|
|
|
if (optionals.attachementUi) {
|
|
const attachmentValues = (optionals.attachementUi as IDataObject)
|
|
.attachmentValues as IDataObject;
|
|
|
|
if (attachmentValues) {
|
|
const item = items[i];
|
|
|
|
if (item.binary === undefined) {
|
|
throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', {
|
|
itemIndex: i,
|
|
});
|
|
}
|
|
|
|
const binaryPropertyName = attachmentValues.binaryProperty as string;
|
|
|
|
if (item.binary[binaryPropertyName] === undefined) {
|
|
throw new NodeOperationError(
|
|
this.getNode(),
|
|
`No binary data property '${binaryPropertyName}' does not exists on item!`,
|
|
{ itemIndex: i },
|
|
);
|
|
}
|
|
|
|
const binaryData = item.binary[binaryPropertyName];
|
|
const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
|
|
options = {
|
|
formData: {
|
|
attachment: {
|
|
value: dataBuffer,
|
|
options: {
|
|
contentType: binaryData.mimeType,
|
|
filename: binaryData.fileName,
|
|
},
|
|
},
|
|
_json: JSON.stringify(body),
|
|
},
|
|
};
|
|
|
|
body = {};
|
|
}
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
`/case/task/${taskId}/log`,
|
|
body,
|
|
qs,
|
|
'',
|
|
options,
|
|
);
|
|
}
|
|
|
|
if (operation === 'executeResponder') {
|
|
const logId = this.getNodeParameter('id', i);
|
|
const responderId = this.getNodeParameter('responder', i) as string;
|
|
let body: IDataObject;
|
|
let response;
|
|
responseData = [];
|
|
body = {
|
|
responderId,
|
|
objectId: logId,
|
|
objectType: 'case_task_log',
|
|
};
|
|
response = await theHiveApiRequest.call(
|
|
this,
|
|
'POST',
|
|
'/connector/cortex/action' as string,
|
|
body,
|
|
);
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'listAction',
|
|
},
|
|
{
|
|
_name: 'filter',
|
|
_and: [
|
|
{
|
|
_field: 'cortexId',
|
|
_value: response.cortexId,
|
|
},
|
|
{
|
|
_field: 'objectId',
|
|
_value: response.objectId,
|
|
},
|
|
{
|
|
_field: 'startDate',
|
|
_value: response.startDate,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
qs.name = 'log-actions';
|
|
do {
|
|
response = await theHiveApiRequest.call(this, 'POST', '/v1/query', body, qs);
|
|
} while (response.status === 'Waiting' || response.status === 'InProgress');
|
|
|
|
responseData = response;
|
|
}
|
|
|
|
if (operation === 'get') {
|
|
const logId = this.getNodeParameter('id', i) as string;
|
|
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'getLog',
|
|
idOrName: logId,
|
|
},
|
|
],
|
|
};
|
|
|
|
qs.name = `get-log-${logId}`;
|
|
} else {
|
|
method = 'POST';
|
|
|
|
endpoint = '/case/task/log/_search';
|
|
|
|
body.query = { _id: logId };
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
|
|
if (operation === 'getAll') {
|
|
const credentials = await this.getCredentials('theHiveApi');
|
|
|
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
|
|
const version = credentials.apiVersion;
|
|
|
|
const taskId = this.getNodeParameter('taskId', i) as string;
|
|
|
|
let endpoint;
|
|
|
|
let method;
|
|
|
|
let body: IDataObject = {};
|
|
|
|
let limit = undefined;
|
|
|
|
if (!returnAll) {
|
|
limit = this.getNodeParameter('limit', i);
|
|
}
|
|
|
|
if (version === 'v1') {
|
|
endpoint = '/v1/query';
|
|
|
|
method = 'POST';
|
|
|
|
body = {
|
|
query: [
|
|
{
|
|
_name: 'getTask',
|
|
idOrName: taskId,
|
|
},
|
|
{
|
|
_name: 'logs',
|
|
},
|
|
],
|
|
};
|
|
|
|
if (limit !== undefined) {
|
|
//@ts-ignore
|
|
prepareRangeQuery(`0-${limit}`, body);
|
|
}
|
|
|
|
qs.name = 'case-task-logs';
|
|
} else {
|
|
method = 'POST';
|
|
|
|
endpoint = '/case/task/log/_search';
|
|
|
|
if (limit !== undefined) {
|
|
qs.range = `0-${limit}`;
|
|
}
|
|
|
|
body.query = And(Parent('task', Id(taskId)));
|
|
}
|
|
|
|
responseData = await theHiveApiRequest.call(this, method, endpoint, body, qs);
|
|
}
|
|
}
|
|
|
|
const executionData = this.helpers.constructExecutionMetaData(
|
|
this.helpers.returnJsonArray(responseData),
|
|
{ itemData: { item: i } },
|
|
);
|
|
returnData.push(...executionData);
|
|
} catch (error) {
|
|
if (this.continueOnFail()) {
|
|
const executionData = this.helpers.constructExecutionMetaData(
|
|
this.helpers.returnJsonArray({ error: error.message }),
|
|
{ itemData: { item: i } },
|
|
);
|
|
returnData.push(...executionData);
|
|
continue;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
return this.prepareOutputData(returnData);
|
|
}
|
|
}
|