import { NodeConnectionType, NodeOperationError } from 'n8n-workflow'; import type { IWebhookFunctions, INodeExecutionData, IDataObject } from 'n8n-workflow'; type WebhookParameters = { httpMethod: string; responseMode: string; responseData: string; responseCode?: number; //typeVersion <= 1.1 options?: { responseData?: string; responseCode?: { values?: { responseCode: number; customCode?: number; }; }; noResponseBody?: boolean; }; }; export const getResponseCode = (parameters: WebhookParameters) => { if (parameters.responseCode) { return parameters.responseCode; } const responseCodeOptions = parameters.options; if (responseCodeOptions?.responseCode?.values) { const { responseCode, customCode } = responseCodeOptions.responseCode.values; if (customCode) { return customCode; } return responseCode; } return 200; }; export const getResponseData = (parameters: WebhookParameters) => { const { responseData, responseMode, options } = parameters; if (responseData) return responseData; if (responseMode === 'onReceived') { const data = options?.responseData; if (data) return data; } if (options?.noResponseBody) return 'noData'; return undefined; }; export const configuredOutputs = (parameters: WebhookParameters) => { const httpMethod = parameters.httpMethod as string | string[]; if (!Array.isArray(httpMethod)) return [ { type: `${NodeConnectionType.Main}`, displayName: httpMethod, }, ]; const outputs = httpMethod.map((method) => { return { type: `${NodeConnectionType.Main}`, displayName: method, }; }); return outputs; }; export const setupOutputConnection = ( ctx: IWebhookFunctions, method: string, additionalData: { jwtPayload?: IDataObject; }, ) => { const httpMethod = ctx.getNodeParameter('httpMethod', []) as string[] | string; let webhookUrl = ctx.getNodeWebhookUrl('default') as string; const executionMode = ctx.getMode() === 'manual' ? 'test' : 'production'; if (executionMode === 'test') { webhookUrl = webhookUrl.replace('/webhook/', '/webhook-test/'); } // multi methods could be set in settings of node, so we need to check if it's an array if (!Array.isArray(httpMethod)) { return (outputData: INodeExecutionData): INodeExecutionData[][] => { outputData.json.webhookUrl = webhookUrl; outputData.json.executionMode = executionMode; if (additionalData?.jwtPayload) { outputData.json.jwtPayload = additionalData.jwtPayload; } return [[outputData]]; }; } const outputIndex = httpMethod.indexOf(method.toUpperCase()); const outputs: INodeExecutionData[][] = httpMethod.map(() => []); return (outputData: INodeExecutionData): INodeExecutionData[][] => { outputData.json.webhookUrl = webhookUrl; outputData.json.executionMode = executionMode; if (additionalData?.jwtPayload) { outputData.json.jwtPayload = additionalData.jwtPayload; } outputs[outputIndex] = [outputData]; return outputs; }; }; export const isIpWhitelisted = ( whitelist: string | string[] | undefined, ips: string[], ip?: string, ) => { if (whitelist === undefined || whitelist === '') { return true; } if (!Array.isArray(whitelist)) { whitelist = whitelist.split(',').map((entry) => entry.trim()); } for (const address of whitelist) { if (ip && ip.includes(address)) { return true; } if (ips.some((entry) => entry.includes(address))) { return true; } } return false; }; export const checkResponseModeConfiguration = (context: IWebhookFunctions) => { const responseMode = context.getNodeParameter('responseMode', 'onReceived') as string; const connectedNodes = context.getChildNodes(context.getNode().name); const isRespondToWebhookConnected = connectedNodes.some( (node) => node.type === 'n8n-nodes-base.respondToWebhook', ); if (!isRespondToWebhookConnected && responseMode === 'responseNode') { throw new NodeOperationError( context.getNode(), new Error('No Respond to Webhook node found in the workflow'), { description: 'Insert a Respond to Webhook node to your workflow to respond to the webhook or choose another option for the “Respond” parameter', }, ); } if (isRespondToWebhookConnected && responseMode !== 'responseNode') { throw new NodeOperationError( context.getNode(), new Error('Webhook node not correctly configured'), { description: 'Set the “Respond” parameter to “Using Respond to Webhook Node” or remove the Respond to Webhook node', }, ); } };