mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
fix(TheHive Node): fixes for node issues
This commit is contained in:
parent
2f4649cdf4
commit
ca9eca9ae9
|
@ -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',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
|
@ -4,8 +4,8 @@ export const logOperations: INodeProperties[] = [
|
|||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
type: 'options',
|
||||
required: true,
|
||||
default: 'getAll',
|
||||
displayOptions: {
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in a new issue