mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
feat(MISP Node): Rest search operations (#9196)
This commit is contained in:
parent
9b3ac1648f
commit
b694e7743e
|
@ -7,7 +7,7 @@ import type {
|
|||
IHttpRequestMethods,
|
||||
IRequestOptions,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeApiError, NodeOperationError, jsonParse } from 'n8n-workflow';
|
||||
|
||||
import type { MispCredentials } from './types';
|
||||
|
||||
|
@ -79,6 +79,57 @@ export async function mispApiRequestAllItems(this: IExecuteFunctions, endpoint:
|
|||
return responseData;
|
||||
}
|
||||
|
||||
export async function mispApiRestSearch(
|
||||
this: IExecuteFunctions,
|
||||
resource: 'attributes' | 'events' | 'objects',
|
||||
itemIndex: number,
|
||||
) {
|
||||
let body: IDataObject = {};
|
||||
const useJson = this.getNodeParameter('useJson', itemIndex) as boolean;
|
||||
|
||||
if (useJson) {
|
||||
const json = this.getNodeParameter('jsonOutput', itemIndex);
|
||||
if (typeof json === 'string') {
|
||||
body = jsonParse(json);
|
||||
} else {
|
||||
body = json as IDataObject;
|
||||
}
|
||||
} else {
|
||||
const value = this.getNodeParameter('value', itemIndex) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', itemIndex);
|
||||
|
||||
body.value = value;
|
||||
|
||||
if (Object.keys(additionalFields).length) {
|
||||
if (additionalFields.tags) {
|
||||
additionalFields.tags = (additionalFields.tags as string)
|
||||
.split(',')
|
||||
.map((tag) => tag.trim());
|
||||
}
|
||||
Object.assign(body, additionalFields);
|
||||
}
|
||||
}
|
||||
|
||||
const endpoint = `/${resource}/restSearch`;
|
||||
const { response } = await mispApiRequest.call(this, 'POST', endpoint, body);
|
||||
|
||||
if (response) {
|
||||
if (resource === 'attributes') {
|
||||
return response.Attribute;
|
||||
}
|
||||
|
||||
if (resource === 'events') {
|
||||
return (response as IDataObject[]).map((event) => event.Event);
|
||||
}
|
||||
|
||||
if (resource === 'objects') {
|
||||
return (response as IDataObject[]).map((obj) => obj.Object);
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function throwOnEmptyUpdate(
|
||||
this: IExecuteFunctions,
|
||||
resource: string,
|
||||
|
|
|
@ -10,6 +10,7 @@ import type {
|
|||
import {
|
||||
mispApiRequest,
|
||||
mispApiRequestAllItems,
|
||||
mispApiRestSearch,
|
||||
throwOnEmptyUpdate,
|
||||
throwOnInvalidUrl,
|
||||
throwOnMissingSharingGroup,
|
||||
|
@ -28,6 +29,8 @@ import {
|
|||
galaxyOperations,
|
||||
noticelistFields,
|
||||
noticelistOperations,
|
||||
objectOperations,
|
||||
objectFields,
|
||||
organisationFields,
|
||||
organisationOperations,
|
||||
tagFields,
|
||||
|
@ -91,6 +94,10 @@ export class Misp implements INodeType {
|
|||
name: 'Noticelist',
|
||||
value: 'noticelist',
|
||||
},
|
||||
{
|
||||
name: 'Object',
|
||||
value: 'object',
|
||||
},
|
||||
{
|
||||
name: 'Organisation',
|
||||
value: 'organisation',
|
||||
|
@ -122,6 +129,8 @@ export class Misp implements INodeType {
|
|||
...galaxyFields,
|
||||
...noticelistOperations,
|
||||
...noticelistFields,
|
||||
...objectOperations,
|
||||
...objectFields,
|
||||
...organisationOperations,
|
||||
...organisationFields,
|
||||
...tagOperations,
|
||||
|
@ -233,6 +242,12 @@ export class Misp implements INodeType {
|
|||
// ----------------------------------------
|
||||
|
||||
responseData = await mispApiRequestAllItems.call(this, '/attributes');
|
||||
} else if (operation === 'search') {
|
||||
// ----------------------------------------
|
||||
// attribute: search
|
||||
// ----------------------------------------
|
||||
|
||||
responseData = await mispApiRestSearch.call(this, 'attributes', i);
|
||||
} else if (operation === 'update') {
|
||||
// ----------------------------------------
|
||||
// attribute: update
|
||||
|
@ -300,6 +315,12 @@ export class Misp implements INodeType {
|
|||
// ----------------------------------------
|
||||
|
||||
responseData = await mispApiRequestAllItems.call(this, '/events');
|
||||
} else if (operation === 'search') {
|
||||
// ----------------------------------------
|
||||
// event: search
|
||||
// ----------------------------------------
|
||||
|
||||
responseData = await mispApiRestSearch.call(this, 'events', i);
|
||||
} else if (operation === 'publish') {
|
||||
// ----------------------------------------
|
||||
// event: publish
|
||||
|
@ -500,6 +521,17 @@ export class Misp implements INodeType {
|
|||
}>;
|
||||
responseData = responseData.map((entry) => entry.Noticelist);
|
||||
}
|
||||
} else if (resource === 'object') {
|
||||
// **********************************************************************
|
||||
// object
|
||||
// **********************************************************************
|
||||
if (operation === 'search') {
|
||||
// ----------------------------------------
|
||||
// attribute: search
|
||||
// ----------------------------------------
|
||||
|
||||
responseData = await mispApiRestSearch.call(this, 'objects', i);
|
||||
}
|
||||
} else if (resource === 'organisation') {
|
||||
// **********************************************************************
|
||||
// organisation
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
import type { INodeProperties } from 'n8n-workflow';
|
||||
import { updateDisplayOptions } from '../../../utils/utilities';
|
||||
import { searchProperties } from './common.descriptions';
|
||||
|
||||
const searchDisplayOptions = {
|
||||
show: {
|
||||
resource: ['attribute'],
|
||||
operation: ['search'],
|
||||
},
|
||||
};
|
||||
|
||||
const searchDescription = updateDisplayOptions(searchDisplayOptions, searchProperties);
|
||||
|
||||
export const attributeOperations: INodeProperties[] = [
|
||||
{
|
||||
|
@ -32,6 +43,11 @@ export const attributeOperations: INodeProperties[] = [
|
|||
value: 'getAll',
|
||||
action: 'Get many attributes',
|
||||
},
|
||||
{
|
||||
name: 'Search',
|
||||
value: 'search',
|
||||
action: 'Get a filtered list of attributes',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
|
@ -226,6 +242,11 @@ export const attributeFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// attribute: search
|
||||
// ----------------------------------------
|
||||
...searchDescription,
|
||||
|
||||
// ----------------------------------------
|
||||
// attribute: update
|
||||
// ----------------------------------------
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
import type { INodeProperties } from 'n8n-workflow';
|
||||
import { updateDisplayOptions } from '../../../utils/utilities';
|
||||
import { searchProperties } from './common.descriptions';
|
||||
|
||||
const searchDisplayOptions = {
|
||||
show: {
|
||||
resource: ['event'],
|
||||
operation: ['search'],
|
||||
},
|
||||
};
|
||||
|
||||
const searchDescription = updateDisplayOptions(searchDisplayOptions, searchProperties);
|
||||
|
||||
export const eventOperations: INodeProperties[] = [
|
||||
{
|
||||
|
@ -37,6 +48,11 @@ export const eventOperations: INodeProperties[] = [
|
|||
value: 'publish',
|
||||
action: 'Publish an event',
|
||||
},
|
||||
{
|
||||
name: 'Search',
|
||||
value: 'search',
|
||||
action: 'Get a filtered list of events',
|
||||
},
|
||||
{
|
||||
name: 'Unpublish',
|
||||
value: 'unpublish',
|
||||
|
@ -295,6 +311,11 @@ export const eventFields: INodeProperties[] = [
|
|||
},
|
||||
},
|
||||
|
||||
// ----------------------------------------
|
||||
// event: search
|
||||
// ----------------------------------------
|
||||
...searchDescription,
|
||||
|
||||
// ----------------------------------------
|
||||
// event: update
|
||||
// ----------------------------------------
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import type { INodeProperties } from 'n8n-workflow';
|
||||
import { updateDisplayOptions } from '../../../utils/utilities';
|
||||
import { searchProperties } from './common.descriptions';
|
||||
|
||||
const searchDisplayOptions = {
|
||||
show: {
|
||||
resource: ['object'],
|
||||
operation: ['search'],
|
||||
},
|
||||
};
|
||||
|
||||
const searchDescription = updateDisplayOptions(searchDisplayOptions, searchProperties);
|
||||
|
||||
export const objectOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['object'],
|
||||
},
|
||||
},
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Search',
|
||||
value: 'search',
|
||||
action: 'Get a filtered list of objects',
|
||||
},
|
||||
],
|
||||
default: 'search',
|
||||
},
|
||||
];
|
||||
|
||||
export const objectFields: INodeProperties[] = [
|
||||
// ----------------------------------------
|
||||
// event: search
|
||||
// ----------------------------------------
|
||||
...searchDescription,
|
||||
];
|
|
@ -0,0 +1,102 @@
|
|||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const searchProperties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Use JSON to Specify Fields',
|
||||
name: 'useJson',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to use JSON to specify the fields for the search request',
|
||||
},
|
||||
{
|
||||
displayName: 'JSON',
|
||||
name: 'jsonOutput',
|
||||
type: 'json',
|
||||
description:
|
||||
'Get more info at {YOUR_BASE_URL_SPECIFIED_IN_CREDENTIALS}/api/openapi#operation/restSearchAttributes',
|
||||
typeOptions: {
|
||||
rows: 5,
|
||||
},
|
||||
default: '{\n "value": "search value",\n "type": "text"\n}\n',
|
||||
validateType: 'object',
|
||||
displayOptions: {
|
||||
show: {
|
||||
useJson: [true],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
required: true,
|
||||
placeholder: 'e.g. 127.0.0.1',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
useJson: [false],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
useJson: [false],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Category',
|
||||
name: 'category',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. Internal reference',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Deleted',
|
||||
name: 'deleted',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Search All',
|
||||
name: 'searchall',
|
||||
type: 'string',
|
||||
description:
|
||||
'Search by matching any tag names, event descriptions, attribute values or attribute comments',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
hide: {
|
||||
'/resource': ['attribute'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. tag1,tag2',
|
||||
hint: 'Comma-separated list of tags',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. text',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Published',
|
||||
name: 'published',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
|
@ -4,6 +4,7 @@ export * from './EventTagDescription';
|
|||
export * from './FeedDescription';
|
||||
export * from './GalaxyDescription';
|
||||
export * from './NoticelistDescription';
|
||||
export * from './ObjectDescription';
|
||||
export * from './OrganisationDescription';
|
||||
export * from './TagDescription';
|
||||
export * from './UserDescription';
|
||||
|
|
Loading…
Reference in a new issue