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';
|
||||
|
||||
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),
|
||||
|
|
Loading…
Reference in a new issue