fix(TheHive Node): fixes for node issues

This commit is contained in:
Michael Kret 2022-10-21 19:46:31 +03:00 committed by GitHub
parent 2f4649cdf4
commit ca9eca9ae9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 277 additions and 124 deletions

View file

@ -1,4 +1,5 @@
import {
IAuthenticate,
IAuthenticateGeneric,
ICredentialTestRequest,
ICredentialType,
@ -55,14 +56,14 @@ export class TheHiveApi implements ICredentialType {
type: 'generic',
properties: {
headers: {
Authorization: '=Bearer {{$credentials.ApiKey}}',
Authorization: '=Bearer {{$credentials?.ApiKey}}',
},
},
};
test: ICredentialTestRequest = {
request: {
baseURL: '={{$credentials.url}}',
url: '/api/alert',
baseURL: `={{$credentials?.url}}`,
url: '/api/case',
},
};
}

View file

@ -78,7 +78,11 @@ export function prepareOptional(optionals: IDataObject): IDataObject {
} else if (moment(optionals[key] as string, moment.ISO_8601).isValid()) {
response[key] = Date.parse(optionals[key] as string);
} else if (key === 'artifacts') {
response[key] = JSON.parse(optionals[key] as string);
try {
response[key] = JSON.parse(optionals[key] as string);
} catch (error) {
throw new Error('Invalid JSON for artifacts');
}
} else if (key === 'tags') {
response[key] = splitTags(optionals[key] as string);
} else {
@ -96,15 +100,26 @@ export async function prepareCustomFields(
): Promise<IDataObject | undefined> {
// Check if the additionalFields object contains customFields
if (jsonParameters === true) {
const customFieldsJson = additionalFields.customFieldsJson;
let customFieldsJson = additionalFields.customFieldsJson;
// Delete from additionalFields as some operations (e.g. alert:update) do not run prepareOptional
// which would remove the extra fields
delete additionalFields.customFieldsJson;
if (typeof customFieldsJson === 'string') {
return JSON.parse(customFieldsJson);
} else if (typeof customFieldsJson === 'object') {
return customFieldsJson as IDataObject;
try {
customFieldsJson = JSON.parse(customFieldsJson);
} catch (error) {
throw new Error('Invalid JSON for customFields');
}
}
if (typeof customFieldsJson === 'object') {
const customFields = Object.keys(customFieldsJson as IDataObject).reduce((acc, curr) => {
acc[`customFields.${curr}`] = (customFieldsJson as IDataObject)[curr];
return acc;
}, {} as IDataObject);
return customFields;
} else if (customFieldsJson) {
throw Error('customFieldsJson value is invalid');
}
@ -136,9 +151,8 @@ export async function prepareCustomFields(
// Might be able to do some type conversions here if needed, TODO
acc[fieldName] = {
[referenceTypeMapping[fieldName]]: curr.value,
};
const updatedField = `customFields.${fieldName}.${[referenceTypeMapping[fieldName]]}`;
acc[updatedField] = curr.value;
return acc;
},
{} as IDataObject,
@ -151,18 +165,10 @@ export async function prepareCustomFields(
}
export function buildCustomFieldSearch(customFields: IDataObject): IDataObject[] {
const customFieldTypes = ['boolean', 'date', 'float', 'integer', 'number', 'string'];
const searchQueries: IDataObject[] = [];
Object.keys(customFields).forEach((customFieldName) => {
const customField = customFields[customFieldName] as IDataObject;
// Figure out the field type from the object's keys
const fieldType = Object.keys(customField).filter(
(key) => customFieldTypes.indexOf(key) > -1,
)[0];
const fieldValue = customField[fieldType];
searchQueries.push(Eq(`customFields.${customFieldName}.${fieldType}`, fieldValue));
searchQueries.push(Eq(customFieldName, customFields[customFieldName]));
});
return searchQueries;
}

View file

@ -22,8 +22,6 @@ import { taskFields, taskOperations } from './descriptions/TaskDescription';
import { logFields, logOperations } from './descriptions/LogDescription';
import { Buffer } from 'buffer';
import { And, Between, ContainsString, Eq, Id, In, IQueryObject, Parent } from './QueryFunctions';
import {
@ -37,6 +35,8 @@ import {
theHiveApiRequest,
} from './GenericFunctions';
import { set } from 'lodash';
export class TheHive implements INodeType {
description: INodeTypeDescription = {
displayName: 'TheHive',
@ -396,10 +396,15 @@ export class TheHive implements INodeType {
source: this.getNodeParameter('source', i),
sourceRef: this.getNodeParameter('sourceRef', i),
follow: this.getNodeParameter('follow', i, true),
customFields,
...prepareOptional(additionalFields),
};
if (customFields) {
Object.keys(customFields).forEach((key) => {
set(body, key, customFields[key]);
});
}
const artifactUi = this.getNodeParameter('artifactUi', i) as IDataObject;
if (artifactUi) {
@ -510,8 +515,18 @@ export class TheHive implements INodeType {
if (operation === 'get') {
const alertId = this.getNodeParameter('id', i) as string;
const includeSimilar = this.getNodeParameter(
'options.includeSimilar',
i,
false,
) as boolean;
const qs: IDataObject = {};
responseData = await theHiveApiRequest.call(this, 'GET', `/alert/${alertId}`, {});
if (includeSimilar) {
qs.similarity = true;
}
responseData = await theHiveApiRequest.call(this, 'GET', `/alert/${alertId}`, {}, qs);
}
if (operation === 'getAll') {
const credentials = await this.getCredentials('theHiveApi');
@ -665,7 +680,7 @@ export class TheHive implements INodeType {
delete updateFields.artifactUi;
const body: IDataObject = {
customFields,
...customFields,
};
Object.assign(body, updateFields);
@ -1272,10 +1287,15 @@ export class TheHive implements INodeType {
flag: this.getNodeParameter('flag', i),
tlp: this.getNodeParameter('tlp', i),
tags: splitTags(this.getNodeParameter('tags', i) as string),
customFields,
...prepareOptional(options),
};
if (customFields) {
Object.keys(customFields).forEach((key) => {
set(body, key, customFields[key]);
});
}
responseData = await theHiveApiRequest.call(this, 'POST', '/case' as string, body);
}
@ -1415,7 +1435,7 @@ export class TheHive implements INodeType {
const customFields = await prepareCustomFields.call(this, updateFields, jsonParameters);
const body: IDataObject = {
customFields,
...customFields,
...prepareOptional(updateFields),
};

View file

@ -7,6 +7,7 @@ import {
INodeTypeDescription,
IWebhookResponseData,
} from 'n8n-workflow';
import { eventsDescription } from './descriptions/EventsDescription';
export class TheHiveTrigger implements INodeType {
description: INodeTypeDescription = {
@ -14,7 +15,7 @@ export class TheHiveTrigger implements INodeType {
name: 'theHiveTrigger',
icon: 'file:thehive.svg',
group: ['trigger'],
version: 1,
version: [1, 2],
description: 'Starts the workflow when TheHive events occur',
defaults: {
name: 'TheHive Trigger',
@ -29,98 +30,7 @@ export class TheHiveTrigger implements INodeType {
path: 'webhook',
},
],
properties: [
{
displayName: 'Events',
name: 'events',
type: 'multiOptions',
default: [],
required: true,
description: 'Events types',
options: [
{
name: '*',
value: '*',
description: 'Any time any event is triggered (Wildcard Event)',
},
{
name: 'Alert Created',
value: 'alert_create',
description: 'Triggered when an alert is created',
},
{
name: 'Alert Deleted',
value: 'alert_delete',
description: 'Triggered when an alert is deleted',
},
{
name: 'Alert Updated',
value: 'alert_update',
description: 'Triggered when an alert is updated',
},
{
name: 'Case Created',
value: 'case_create',
description: 'Triggered when a case is created',
},
{
name: 'Case Deleted',
value: 'case_delete',
description: 'Triggered when a case is deleted',
},
{
name: 'Case Updated',
value: 'case_update',
description: 'Triggered when a case is updated',
},
{
name: 'Log Created',
value: 'case_task_log_create',
description: 'Triggered when a task log is created',
},
{
name: 'Log Deleted',
value: 'case_task_log_delete',
description: 'Triggered when a task log is deleted',
},
{
name: 'Log Updated',
value: 'case_task_log_update',
description: 'Triggered when a task log is updated',
},
{
name: 'Observable Created',
value: 'case_artifact_create',
description: 'Triggered when an observable is created',
},
{
name: 'Observable Deleted',
value: 'case_artifact_delete',
description: 'Triggered when an observable is deleted',
},
{
name: 'Observable Updated',
value: 'case_artifact_update',
description: 'Triggered when an observable is updated',
},
{
name: 'Task Created',
value: 'case_task_create',
description: 'Triggered when a task is created',
},
{
name: 'Task Deleted',
value: 'case_task_delete',
description: 'Triggered when a task is deleted',
},
{
name: 'Task Updated',
value: 'case_task_update',
description: 'Triggered when a task is updated',
},
],
},
],
properties: [...eventsDescription],
};
// @ts-ignore (because of request)
webhookMethods = {
@ -150,6 +60,7 @@ export class TheHiveTrigger implements INodeType {
// Replace Creation with Create for TheHive 3 support
const operation = (bodyData.operation as string).replace('Creation', 'Create');
const event = `${(bodyData.objectType as string).toLowerCase()}_${operation.toLowerCase()}`;
if (events.indexOf('*') === -1 && events.indexOf(event) === -1) {
return {};
}

View file

@ -762,6 +762,32 @@ export const alertFields: INodeProperties[] = [
},
],
},
{
displayName: 'Options',
name: 'options',
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'alert',
],
},
},
type: 'collection',
placeholder: 'Add Option',
default: {},
options: [
{
displayName: 'Include Similar Cases',
name: 'includeSimilar',
type: 'boolean',
description: 'Whether to include similar cases',
default: false,
},
],
},
{
displayName: 'Filters',
name: 'filters',

View file

@ -0,0 +1,189 @@
import { INodeProperties } from 'n8n-workflow';
export const eventsDescription: INodeProperties[] = [
{
displayName: 'Events',
name: 'events',
type: 'multiOptions',
default: [],
required: true,
description: 'Events types',
displayOptions: {
show: {
'@version': [1],
},
},
options: [
{
name: '*',
value: '*',
description: 'Any time any event is triggered (Wildcard Event)',
},
{
name: 'Alert Created',
value: 'alert_create',
description: 'Triggered when an alert is created',
},
{
name: 'Alert Deleted',
value: 'alert_delete',
description: 'Triggered when an alert is deleted',
},
{
name: 'Alert Updated',
value: 'alert_update',
description: 'Triggered when an alert is updated',
},
{
name: 'Case Created',
value: 'case_create',
description: 'Triggered when a case is created',
},
{
name: 'Case Deleted',
value: 'case_delete',
description: 'Triggered when a case is deleted',
},
{
name: 'Case Updated',
value: 'case_update',
description: 'Triggered when a case is updated',
},
{
name: 'Log Created',
value: 'case_task_log_create',
description: 'Triggered when a task log is created',
},
{
name: 'Log Deleted',
value: 'case_task_log_delete',
description: 'Triggered when a task log is deleted',
},
{
name: 'Log Updated',
value: 'case_task_log_update',
description: 'Triggered when a task log is updated',
},
{
name: 'Observable Created',
value: 'case_artifact_create',
description: 'Triggered when an observable is created',
},
{
name: 'Observable Deleted',
value: 'case_artifact_delete',
description: 'Triggered when an observable is deleted',
},
{
name: 'Observable Updated',
value: 'case_artifact_update',
description: 'Triggered when an observable is updated',
},
{
name: 'Task Created',
value: 'case_task_create',
description: 'Triggered when a task is created',
},
{
name: 'Task Deleted',
value: 'case_task_delete',
description: 'Triggered when a task is deleted',
},
{
name: 'Task Updated',
value: 'case_task_update',
description: 'Triggered when a task is updated',
},
],
},
{
displayName: 'Events',
name: 'events',
type: 'multiOptions',
default: [],
required: true,
description: 'Events types',
displayOptions: {
show: {
'@version': [2],
},
},
options: [
{
name: '*',
value: '*',
description: 'Any time any event is triggered (Wildcard Event)',
},
{
name: 'Alert Created',
value: 'alert_create',
description: 'Triggered when an alert is created',
},
{
name: 'Alert Deleted',
value: 'alert_delete',
description: 'Triggered when an alert is deleted',
},
{
name: 'Alert Updated',
value: 'alert_update',
description: 'Triggered when an alert is updated',
},
{
name: 'Case Created',
value: 'case_create',
description: 'Triggered when a case is created',
},
{
name: 'Case Deleted',
value: 'case_delete',
description: 'Triggered when a case is deleted',
},
{
name: 'Case Updated',
value: 'case_update',
description: 'Triggered when a case is updated',
},
{
name: 'Log Created',
value: 'case_task_log_create',
description: 'Triggered when a task log is created',
},
{
name: 'Log Deleted',
value: 'case_task_log_delete',
description: 'Triggered when a task log is deleted',
},
{
name: 'Log Updated',
value: 'case_task_log_update',
description: 'Triggered when a task log is updated',
},
{
name: 'Observable Created',
value: 'case_artifact_create',
description: 'Triggered when an observable is created',
},
{
name: 'Observable Deleted',
value: 'case_artifact_delete',
description: 'Triggered when an observable is deleted',
},
{
name: 'Observable Updated',
value: 'case_artifact_update',
description: 'Triggered when an observable is updated',
},
{
name: 'Task Created',
value: 'case_task_create',
description: 'Triggered when a task is created',
},
{
name: 'Task Updated',
value: 'case_task_update',
description: 'Triggered when a task is updated',
},
],
},
];

View file

@ -4,8 +4,8 @@ export const logOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
type: 'options',
required: true,
default: 'getAll',
displayOptions: {

View file

@ -101,7 +101,7 @@ export const observableFields: INodeProperties[] = [
},
},
description:
'Type of the observable. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
},
{
displayName: 'Data',
@ -448,7 +448,7 @@ export const observableFields: INodeProperties[] = [
loadOptionsMethod: 'loadObservableTypes',
},
description:
'Type of the observable. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
},
{
displayName: 'Date Range',