diff --git a/packages/nodes-base/nodes/Jira/JiraTrigger.node.ts b/packages/nodes-base/nodes/Jira/JiraTrigger.node.ts index 99b4846725..bd928f3084 100644 --- a/packages/nodes-base/nodes/Jira/JiraTrigger.node.ts +++ b/packages/nodes-base/nodes/Jira/JiraTrigger.node.ts @@ -4,10 +4,12 @@ import { } from 'n8n-core'; import { + ICredentialDataDecryptedObject, IDataObject, INodeType, INodeTypeDescription, IWebhookResponseData, + NodeOperationError, } from 'n8n-workflow'; import { @@ -55,6 +57,17 @@ export class JiraTrigger implements INodeType { }, }, }, + { + name: 'httpQueryAuth', + required: true, + displayOptions: { + show: { + incomingAuthentication: [ + 'queryAuth', + ], + }, + }, + }, ], webhooks: [ { @@ -81,6 +94,23 @@ export class JiraTrigger implements INodeType { ], default: 'cloud', }, + { + displayName: 'Incoming Authentication', + name: 'incomingAuthentication', + type: 'options', + options: [ + { + name: 'Query Auth', + value: 'queryAuth', + }, + { + name: 'None', + value: 'none', + }, + ], + default: 'none', + description: 'If authentication should be activated for the webhook (makes it more secure)', + }, { displayName: 'Events', name: 'events', @@ -379,6 +409,8 @@ export class JiraTrigger implements INodeType { const webhookData = this.getWorkflowStaticData('node'); + const incomingAuthentication = this.getNodeParameter('incomingAuthentication') as string; + if (events.includes('*')) { events = allEvents; } @@ -402,12 +434,30 @@ export class JiraTrigger implements INodeType { body.excludeBody = additionalFields.excludeBody as boolean; } + // tslint:disable-next-line: no-any + const parameters: any = {}; + + if (incomingAuthentication === 'queryAuth') { + let httpQueryAuth; + try{ + httpQueryAuth = await this.getCredentials('httpQueryAuth'); + } catch (e) { + throw new NodeOperationError(this.getNode(), `Could not retrieve HTTP Query Auth credentials: ${e}`); + } + if (!httpQueryAuth.name && !httpQueryAuth.value) { + throw new NodeOperationError(this.getNode(), `HTTP Query Auth credentials are empty`); + } + parameters[encodeURIComponent(httpQueryAuth.name as string)] = Buffer.from(httpQueryAuth.value as string).toString('base64'); + } + if (additionalFields.includeFields) { - // tslint:disable-next-line: no-any - const parameters: any = {}; + for (const field of additionalFields.includeFields as string[]) { parameters[field] = '${' + field + '}'; } + } + + if (Object.keys(parameters).length) { body.url = `${body.url}?${queryString.unescape(queryString.stringify(parameters))}`; } @@ -441,9 +491,46 @@ export class JiraTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { const bodyData = this.getBodyData(); - const queryData = this.getQueryData(); + const queryData = this.getQueryData() as IDataObject; + const response = this.getResponseObject(); - Object.assign(bodyData, queryData); + const incomingAuthentication = this.getNodeParameter('incomingAuthentication') as string; + + if (incomingAuthentication === 'queryAuth') { + let httpQueryAuth: ICredentialDataDecryptedObject | undefined; + + try { + httpQueryAuth = await this.getCredentials('httpQueryAuth'); + } catch (error) { } + + if (httpQueryAuth === undefined || !httpQueryAuth.name || !httpQueryAuth.value) { + + response.status(403).json({ message: 'Auth settings are not valid, some data are missing' }); + + return { + noWebhookResponse: true, + }; + } + + const paramName = httpQueryAuth.name as string; + const paramValue = Buffer.from(httpQueryAuth.value as string).toString('base64'); + + if (!queryData.hasOwnProperty(paramName) || queryData[paramName] !== paramValue) { + + response.status(403).json({ message: 'Provided authentication data is not valid' }); + + return { + noWebhookResponse: true, + }; + } + + delete queryData[paramName]; + + Object.assign(bodyData, queryData); + + } else { + Object.assign(bodyData, queryData); + } return { workflowData: [