mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
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:
parent
dbc02803db
commit
25093b64e6
|
@ -4,10 +4,12 @@ import {
|
||||||
} from 'n8n-core';
|
} from 'n8n-core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ICredentialDataDecryptedObject,
|
||||||
IDataObject,
|
IDataObject,
|
||||||
INodeType,
|
INodeType,
|
||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
IWebhookResponseData,
|
IWebhookResponseData,
|
||||||
|
NodeOperationError,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -55,6 +57,17 @@ export class JiraTrigger implements INodeType {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'httpQueryAuth',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
incomingAuthentication: [
|
||||||
|
'queryAuth',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
webhooks: [
|
webhooks: [
|
||||||
{
|
{
|
||||||
|
@ -81,6 +94,23 @@ export class JiraTrigger implements INodeType {
|
||||||
],
|
],
|
||||||
default: 'cloud',
|
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',
|
displayName: 'Events',
|
||||||
name: 'events',
|
name: 'events',
|
||||||
|
@ -379,6 +409,8 @@ export class JiraTrigger implements INodeType {
|
||||||
|
|
||||||
const webhookData = this.getWorkflowStaticData('node');
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
|
||||||
|
const incomingAuthentication = this.getNodeParameter('incomingAuthentication') as string;
|
||||||
|
|
||||||
if (events.includes('*')) {
|
if (events.includes('*')) {
|
||||||
events = allEvents;
|
events = allEvents;
|
||||||
}
|
}
|
||||||
|
@ -402,12 +434,30 @@ export class JiraTrigger implements INodeType {
|
||||||
body.excludeBody = additionalFields.excludeBody as boolean;
|
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) {
|
if (additionalFields.includeFields) {
|
||||||
// tslint:disable-next-line: no-any
|
|
||||||
const parameters: any = {};
|
|
||||||
for (const field of additionalFields.includeFields as string[]) {
|
for (const field of additionalFields.includeFields as string[]) {
|
||||||
parameters[field] = '${' + field + '}';
|
parameters[field] = '${' + field + '}';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(parameters).length) {
|
||||||
body.url = `${body.url}?${queryString.unescape(queryString.stringify(parameters))}`;
|
body.url = `${body.url}?${queryString.unescape(queryString.stringify(parameters))}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,9 +491,46 @@ export class JiraTrigger implements INodeType {
|
||||||
|
|
||||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||||
const bodyData = this.getBodyData();
|
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 {
|
return {
|
||||||
workflowData: [
|
workflowData: [
|
||||||
|
|
Loading…
Reference in a new issue