feat(Jira Trigger Node): Add optional query auth for security (#3172)

*  Add query auth for Jira Trigger security

*  small fixes:

*  Response with 403 when invalid query authentication

* 👕 Fix linting issues

Co-authored-by: Michael Kret <michael.k@radency.com>
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
This commit is contained in:
pemontto 2022-07-10 09:41:32 +01:00 committed by GitHub
parent dbc02803db
commit 25093b64e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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;
}
if (additionalFields.includeFields) {
// 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) {
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,10 +491,47 @@ export class JiraTrigger implements INodeType {
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const bodyData = this.getBodyData();
const queryData = this.getQueryData();
const queryData = this.getQueryData() as IDataObject;
const response = this.getResponseObject();
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: [
this.helpers.returnJsonArray(bodyData),