import { IExecuteFunctions, BINARY_ENCODING } from 'n8n-core'; import { INodeExecutionData, INodeType, INodeTypeDescription, IDataObject, INodeParameters, ILoadOptionsFunctions, INodePropertyOptions, IBinaryData } from 'n8n-workflow'; import { alertOperations, alertFields, } from './descriptions/AlertDescription'; import { observableOperations, observableFields, } from './descriptions/ObservableDescription'; import { caseOperations, caseFields, } from './descriptions/CaseDescription'; import { taskOperations, taskFields, } from './descriptions/TaskDescription'; import { logOperations, logFields, } from './descriptions/LogDescription'; import { Buffer, } from 'buffer'; import { IQueryObject, Parent, Id, Eq, And, Between, In, ContainsString, } from './QueryFunctions'; import { theHiveApiRequest, mapResource, splitTags, prepareOptional, prepareSortQuery, prepareRangeQuery, } from './GenericFunctions'; export class TheHive implements INodeType { description: INodeTypeDescription = { displayName: 'TheHive', name: 'theHive', icon: 'file:thehive.png', group: ['transform'], subtitle: '={{$parameter["operation"]}} : {{$parameter["resource"]}}', version: 1, description: 'Consume TheHive APIs', defaults: { name: 'TheHive', color: '#f3d02f', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'theHiveApi', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', 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 { // 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 as string, ); 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 { // 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 as string ); 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 loadObservableOptions(this: ILoadOptionsFunctions): Promise { // if v1 is not used we remove 'count' option const version = 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 All',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 loadTaskOptions(this:ILoadOptionsFunctions): Promise{ const version = this.getCredentials('theHiveApi')?.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 All',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{ const version = this.getCredentials('theHiveApi')?.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 All', value: 'getAll', description: 'Get all alerts' }, { 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{ const version = this.getCredentials('theHiveApi')?.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 All', 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 { const items = this.getInputData(); const returnData: IDataObject[] = []; const length = (items.length as unknown) as number; const qs: IDataObject = {}; let responseData; const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; for (let i = 0; i < length; i++) { if (resource === 'alert') { 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 === '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 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(this.getNodeParameter('optionals', i, {}) as INodeParameters) }; const artifactUi = this.getNodeParameter('artifactUi', i)as IDataObject; if (artifactUi) { const artifactValues = (artifactUi as IDataObject).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(',') as string[]; 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 Error('No binary data exists on item!'); } const binaryPropertyName = artifactvalue.binaryProperty as string; if (item.binary[binaryPropertyName] === undefined) { throw new Error(`No binary data property '${binaryPropertyName}' does not exists on item!`); } const binaryData = item.binary[binaryPropertyName] as IBinaryData; 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; responseData = await theHiveApiRequest.call( this, 'GET', `/alert/${alertId}`, {}, ); } if (operation === 'getAll') { const credentials = this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; const version = credentials.apiVersion; const queryAttributs: any = prepareOptional(this.getNodeParameter('filters', i, {}) as INodeParameters); const options = this.getNodeParameter('options', i) as IDataObject; const _searchQuery: IQueryObject = And(); 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 === false) { limit = this.getNodeParameter('limit', i) as number; } 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 as string, body, qs, ); } 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) as IDataObject; 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 updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const artifactUi = updateFields.artifactUi as IDataObject; delete updateFields.artifactUi; const body: IDataObject = {}; Object.assign(body, updateFields); if (artifactUi) { const artifactValues = (artifactUi as IDataObject).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(',') as string[]; 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 Error('No binary data exists on item!'); } const binaryPropertyName = artifactvalue.binaryProperty as string; if (item.binary[binaryPropertyName] === undefined) { throw new Error(`No binary data property '${binaryPropertyName}' does not exists on item!`); } const binaryData = item.binary[binaryPropertyName] as IBinaryData; element.data = `${binaryData.fileName};${binaryData.mimeType};${binaryData.data}`; } artifactData.push(element); } body.artifacts = artifactData; } } responseData = await theHiveApiRequest.call( this, 'PATCH', `/alert/${alertId}` as string, 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 Error('No binary data exists on item!'); } const binaryPropertyName = this.getNodeParameter('binaryProperty', i) as string; if (item.binary[binaryPropertyName] === undefined) { throw new Error(`No binary data property '${binaryPropertyName}' does not exists on item!`); } const binaryData = item.binary[binaryPropertyName] as IBinaryData; options = { formData: { attachment: { value: Buffer.from(binaryData.data, BINARY_ENCODING), 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` as string, body, qs, '', options ); } if(operation === 'get'){ const observableId = this.getNodeParameter('id', i) as string; const credentials = this.getCredentials('theHiveApi') as IDataObject; 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 as string, body, qs, ); } if(operation === 'getAll'){ const credentials = this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; const version = credentials.apiVersion; const options = this.getNodeParameter('options', i) as IDataObject; const caseId = this.getNodeParameter('caseId', i); let endpoint; let method; let body: IDataObject = {}; let limit = undefined; if (returnAll === false) { limit = this.getNodeParameter('limit', i) as number; } 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 as string, body, qs, ); } if(operation === 'search'){ const credentials = this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; const version = credentials.apiVersion; const queryAttributs: any = prepareOptional(this.getNodeParameter('filters', i, {}) as INodeParameters); const _searchQuery: IQueryObject = And(); const options = this.getNodeParameter('options', i) as IDataObject; 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 === false) { limit = this.getNodeParameter('limit', i) as number; } 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 as string, 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}` as string, body, qs, ); responseData = { success: true }; } } if (resource === 'case'){ 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 === '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 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(this.getNodeParameter('options', i, {}) as INodeParameters) }; responseData = await theHiveApiRequest.call( this, 'POST', '/case' as string, body, ); } if(operation === 'get'){ const caseId = this.getNodeParameter('id', i) as string; const credentials = this.getCredentials('theHiveApi') as IDataObject; 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 as string, body, qs, ); } if(operation === 'getAll'){ const credentials = this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; const version = credentials.apiVersion; const queryAttributs: any = prepareOptional(this.getNodeParameter('filters', i, {}) as INodeParameters); const _searchQuery: IQueryObject = And(); const options = this.getNodeParameter('options', i) as IDataObject; 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 === false) { limit = this.getNodeParameter('limit', i) as number; } 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 as string, 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/${id}` as string, 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` as string, 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 = this.getCredentials('theHiveApi') as IDataObject; 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 as string, body, qs, ); } if(operation === 'getAll'){ // get all require a case id (it retursn all tasks for a specific case) const credentials = this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; const version = credentials.apiVersion; const caseId = this.getNodeParameter('caseId', i) as string; const options = this.getNodeParameter('options', i) as IDataObject; let endpoint; let method; let body: IDataObject = {}; let limit = undefined; if (returnAll === false) { limit = this.getNodeParameter('limit', i) as number; } 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 as string, body, qs, ); } if(operation === 'search'){ const credentials = this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; const version = credentials.apiVersion; const queryAttributs: any = prepareOptional(this.getNodeParameter('filters', i, {}) as INodeParameters); const _searchQuery: IQueryObject = And(); const options = this.getNodeParameter('options', i) as IDataObject; 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 === false) { limit = this.getNodeParameter('limit', i) as number; } 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 as string, 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}` as string, 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) as IDataObject; 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 Error('No binary data exists on item!'); } const binaryPropertyName = attachmentValues.binaryProperty as string; if (item.binary[binaryPropertyName] === undefined) { throw new Error(`No binary data property '${binaryPropertyName}' does not exists on item!`); } const binaryData = item.binary[binaryPropertyName] as IBinaryData; options = { formData: { attachment: { value: Buffer.from(binaryData.data, BINARY_ENCODING), options: { contentType: binaryData.mimeType, filename: binaryData.fileName, } }, _json: JSON.stringify(body) } }; body = {}; } } responseData = await theHiveApiRequest.call( this, 'POST', `/case/task/${taskId}/log` as string, 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 = this.getCredentials('theHiveApi') as IDataObject; 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 as string, body, qs, ); } if (operation === 'getAll'){ const credentials = this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; const version = credentials.apiVersion; const taskId = this.getNodeParameter('taskId', i) as string; let endpoint; let method; let body: IDataObject = {}; let limit = undefined; if (returnAll === false) { limit = this.getNodeParameter('limit', i) as number; } 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 as string, body, qs, ); } } if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); } else if (responseData !== undefined) { returnData.push(responseData as IDataObject); } } return [this.helpers.returnJsonArray(returnData)]; } }