From 86fa3a6b9e58ae7c17d03929ab55e161dcddabcb Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Wed, 18 Aug 2021 16:25:05 +0200 Subject: [PATCH 01/30] Updates webhook UUIDs to a new one when duplicating --- .../editor-ui/src/components/DuplicateWorkflowDialog.vue | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue b/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue index 839e00efac..d24776a60e 100644 --- a/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue +++ b/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue @@ -44,6 +44,8 @@ import { workflowHelpers } from "@/components/mixins/workflowHelpers"; import { showMessage } from "@/components/mixins/showMessage"; import TagsDropdown from "@/components/TagsDropdown.vue"; import Modal from "./Modal.vue"; +import { v4 as uuidv4} from 'uuid'; +import { INodeUi } from "../Interface"; export default mixins(showMessage, workflowHelpers).extend({ components: { TagsDropdown, Modal }, @@ -107,6 +109,13 @@ export default mixins(showMessage, workflowHelpers).extend({ return; } + const allNodes = this.$store.getters.allNodes; + allNodes.forEach((node: INodeUi) => { + if (node.webhookId) { + node.webhookId = uuidv4(); + } + }); + this.$data.isSaving = true; const saved = await this.saveAsNewWorkflow({name, tags: this.currentTagIds}); From 82dbbcd2e0e19861d720bc5a3ffa7326844188b0 Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Thu, 19 Aug 2021 10:51:27 +0200 Subject: [PATCH 02/30] Changed the webhook id change code placement --- .../src/components/DuplicateWorkflowDialog.vue | 11 +---------- .../src/components/mixins/workflowHelpers.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue b/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue index d24776a60e..2f570c4ea7 100644 --- a/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue +++ b/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue @@ -44,8 +44,6 @@ import { workflowHelpers } from "@/components/mixins/workflowHelpers"; import { showMessage } from "@/components/mixins/showMessage"; import TagsDropdown from "@/components/TagsDropdown.vue"; import Modal from "./Modal.vue"; -import { v4 as uuidv4} from 'uuid'; -import { INodeUi } from "../Interface"; export default mixins(showMessage, workflowHelpers).extend({ components: { TagsDropdown, Modal }, @@ -109,16 +107,9 @@ export default mixins(showMessage, workflowHelpers).extend({ return; } - const allNodes = this.$store.getters.allNodes; - allNodes.forEach((node: INodeUi) => { - if (node.webhookId) { - node.webhookId = uuidv4(); - } - }); - this.$data.isSaving = true; - const saved = await this.saveAsNewWorkflow({name, tags: this.currentTagIds}); + const saved = await this.saveAsNewWorkflow({name, tags: this.currentTagIds, updateWebhookUrls: true}); if (saved) { this.closeDialog(); diff --git a/packages/editor-ui/src/components/mixins/workflowHelpers.ts b/packages/editor-ui/src/components/mixins/workflowHelpers.ts index ec4acf820c..4521523c69 100644 --- a/packages/editor-ui/src/components/mixins/workflowHelpers.ts +++ b/packages/editor-ui/src/components/mixins/workflowHelpers.ts @@ -39,6 +39,7 @@ import { showMessage } from '@/components/mixins/showMessage'; import { isEqual } from 'lodash'; import mixins from 'vue-typed-mixins'; +import { v4 as uuidv4} from 'uuid'; export const workflowHelpers = mixins( externalHooks, @@ -435,13 +436,20 @@ export const workflowHelpers = mixins( } }, - async saveAsNewWorkflow ({name, tags}: {name?: string, tags?: string[]} = {}): Promise { + async saveAsNewWorkflow ({name, tags, updateWebhookUrls}: {name?: string, tags?: string[], updateWebhookUrls?: boolean} = {}): Promise { try { this.$store.commit('addActiveAction', 'workflowSaving'); const workflowDataRequest: IWorkflowDataUpdate = await this.getWorkflowDataToSave(); // make sure that the new ones are not active workflowDataRequest.active = false; + if (updateWebhookUrls) { + workflowDataRequest.nodes!.forEach(node => { + if (node.webhookId) { + node.webhookId = uuidv4(); + } + }); + } if (name) { workflowDataRequest.name = name.trim(); @@ -452,10 +460,8 @@ export const workflowHelpers = mixins( } const workflowData = await this.restApi().createNewWorkflow(workflowDataRequest); - this.$store.commit('setActive', workflowData.active || false); - this.$store.commit('setWorkflowId', workflowData.id); + this.$store.commit('setWorkflow', workflowData); this.$store.commit('setWorkflowName', {newName: workflowData.name, setStateDirty: false}); - this.$store.commit('setWorkflowSettings', workflowData.settings || {}); this.$store.commit('setStateDirty', false); const createdTags = (workflowData.tags || []) as ITag[]; From 3b73cb6a564c9a0d5c0714d988dccd347e9fe8a8 Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Thu, 19 Aug 2021 15:26:38 +0200 Subject: [PATCH 03/30] Adjustments suggested by @mutdmour --- .../editor-ui/src/components/DuplicateWorkflowDialog.vue | 2 +- .../editor-ui/src/components/mixins/workflowHelpers.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue b/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue index 2f570c4ea7..be8375b51d 100644 --- a/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue +++ b/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue @@ -109,7 +109,7 @@ export default mixins(showMessage, workflowHelpers).extend({ this.$data.isSaving = true; - const saved = await this.saveAsNewWorkflow({name, tags: this.currentTagIds, updateWebhookUrls: true}); + const saved = await this.saveAsNewWorkflow({name, tags: this.currentTagIds, resetWebhookUrls: true}); if (saved) { this.closeDialog(); diff --git a/packages/editor-ui/src/components/mixins/workflowHelpers.ts b/packages/editor-ui/src/components/mixins/workflowHelpers.ts index 4521523c69..656737358a 100644 --- a/packages/editor-ui/src/components/mixins/workflowHelpers.ts +++ b/packages/editor-ui/src/components/mixins/workflowHelpers.ts @@ -436,18 +436,19 @@ export const workflowHelpers = mixins( } }, - async saveAsNewWorkflow ({name, tags, updateWebhookUrls}: {name?: string, tags?: string[], updateWebhookUrls?: boolean} = {}): Promise { + async saveAsNewWorkflow ({name, tags, resetWebhookUrls}: {name?: string, tags?: string[], resetWebhookUrls?: boolean} = {}): Promise { try { this.$store.commit('addActiveAction', 'workflowSaving'); const workflowDataRequest: IWorkflowDataUpdate = await this.getWorkflowDataToSave(); // make sure that the new ones are not active workflowDataRequest.active = false; - if (updateWebhookUrls) { - workflowDataRequest.nodes!.forEach(node => { + if (resetWebhookUrls) { + workflowDataRequest.nodes = workflowDataRequest.nodes!.map(node => { if (node.webhookId) { node.webhookId = uuidv4(); } + return node; }); } From 7da86641d5231fe8d384b8372d7e2dc4ea15b6d4 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 19 Aug 2021 18:29:20 +0200 Subject: [PATCH 04/30] :bug: Fix issue with referencing values before loops --- packages/workflow/src/Workflow.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/workflow/src/Workflow.ts b/packages/workflow/src/Workflow.ts index fb4189d762..57fbe25625 100644 --- a/packages/workflow/src/Workflow.ts +++ b/packages/workflow/src/Workflow.ts @@ -635,6 +635,17 @@ export class Workflow { * @memberof Workflow */ getNodeConnectionOutputIndex(nodeName: string, parentNodeName: string, type = 'main', depth = -1, checkedNodes?: string[]): number | undefined { + const node = this.getNode(parentNodeName); + if (node === null) { + return undefined; + } + const nodeType = this.nodeTypes.getByName(node.type) as INodeType; + if (nodeType.description.outputs.length === 1) { + // If the parent node has only one output, it can only be connected + // to that one. So no further checking is required. + return 0; + } + depth = depth === -1 ? -1 : depth; const newDepth = depth === -1 ? depth : depth - 1; if (depth === 0) { @@ -669,8 +680,8 @@ export class Workflow { } if (checkedNodes!.includes(connection.node)) { - // Node got checked already before - return; + // Node got checked already before so continue with the next one + continue; } outputIndex = this.getNodeConnectionOutputIndex(connection.node, parentNodeName, type, newDepth, checkedNodes); From 178235e148bb539bc4e1d6ecbc2d1d5784ca115a Mon Sep 17 00:00:00 2001 From: Ahsan Virani Date: Fri, 20 Aug 2021 18:08:40 +0200 Subject: [PATCH 05/30] :sparkles: Initial changes for binary data management (#2105) * introduce binary data management * cr * add binary data changes to awsS3 node * add binary data changes to Box node * add binary data changes to CiscoWebex node * add binary data changes to HumaniticAi node * add binary data changes to Jira node * add binary data changes to Line node * add binary data changes to MicrosoftOneDrive node * add binary data changes to MicrosoftOutlook node * add binary data changes to Mindee node * add binary data changes to NocoDB node * add binary data changes to Pushbullet node * add binary data changes to Pushover node * add binary data changes to Raindrop node * add binary data changes to S3 node * add binary data changes to Salesforce node * add binary data changes to Ssh node * add binary data changes to TheHive node * add binary data changes to Twist node * add binary data changes to Twitter node * remove changes not needed right now * :bug: Fix issue with multiple runs * :bug: Revert fix and add support for multiple inputs Co-authored-by: Jan Oberhauser --- packages/core/src/Interfaces.ts | 7 +++--- packages/core/src/NodeExecuteFunctions.ts | 18 +++++++++++++ packages/core/test/WorkflowExecute.test.ts | 2 +- .../nodes-base/nodes/Aws/S3/AwsS3.node.ts | 4 +-- packages/nodes-base/nodes/Box/Box.node.ts | 4 +-- .../nodes/Cisco/Webex/CiscoWebex.node.ts | 4 +-- packages/nodes-base/nodes/Compression.node.ts | 15 +++++------ .../nodes/HumanticAI/HumanticAi.node.ts | 7 +++--- packages/nodes-base/nodes/Jira/Jira.node.ts | 4 +-- packages/nodes-base/nodes/Line/Line.node.ts | 4 +-- .../OneDrive/MicrosoftOneDrive.node.ts | 3 +-- .../Outlook/MicrosoftOutlook.node.ts | 2 +- .../nodes-base/nodes/Mindee/Mindee.node.ts | 7 +++--- .../nodes-base/nodes/NocoDB/NocoDB.node.ts | 7 +++--- .../nodes/Pushbullet/Pushbullet.node.ts | 4 +-- .../nodes/Pushover/Pushover.node.ts | 5 ++-- .../nodes/Raindrop/Raindrop.node.ts | 4 +-- packages/nodes-base/nodes/S3/S3.node.ts | 4 +-- .../nodes/Salesforce/Salesforce.node.ts | 5 ++-- packages/nodes-base/nodes/Ssh/Ssh.node.ts | 5 ++-- .../nodes-base/nodes/TheHive/TheHive.node.ts | 7 +++--- packages/nodes-base/nodes/Twist/Twist.node.ts | 25 +++++++++++++------ .../nodes/Twitter/GenericFunctions.ts | 10 +++++--- .../nodes-base/nodes/WriteBinaryFile.node.ts | 12 ++++----- 24 files changed, 103 insertions(+), 66 deletions(-) diff --git a/packages/core/src/Interfaces.ts b/packages/core/src/Interfaces.ts index 763afdf4b8..52bd80f700 100644 --- a/packages/core/src/Interfaces.ts +++ b/packages/core/src/Interfaces.ts @@ -34,9 +34,10 @@ export interface IProcessMessage { export interface IExecuteFunctions extends IExecuteFunctionsBase { helpers: { prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise; - request: requestPromise.RequestPromiseAPI, - requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise, // tslint:disable-line:no-any - requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise, // tslint:disable-line:no-any + getBinaryDataBuffer(itemIndex: number, propertyName: string): Promise; + request: requestPromise.RequestPromiseAPI; + requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise; // tslint:disable-line:no-any + requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise; // tslint:disable-line:no-any returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[]; }; } diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 218eb097d4..1042257e65 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -59,6 +59,21 @@ const requestPromiseWithDefaults = requestPromise.defaults({ timeout: 300000, // 5 minutes }); +/** + * Returns binary data buffer for given item index and property name. + * + * @export + * @param {ITaskDataConnections} inputData + * @param {number} itemIndex + * @param {string} propertyName + * @param {number} inputIndex + * @returns {Promise} + */ +export async function getBinaryDataBuffer(inputData: ITaskDataConnections, itemIndex: number, propertyName: string, inputIndex: number): Promise { + const binaryData = inputData['main']![inputIndex]![itemIndex]!.binary![propertyName]!; + return Buffer.from(binaryData.data, BINARY_ENCODING); +} + /** * Takes a buffer and converts it into the format n8n uses. It encodes the binary data as * base64 and adds metadata. @@ -763,6 +778,9 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx }, helpers: { prepareBinaryData, + getBinaryDataBuffer(itemIndex: number, propertyName: string, inputIndex = 0): Promise { + return getBinaryDataBuffer.call(this, inputData, itemIndex, propertyName, inputIndex); + }, request: requestPromiseWithDefaults, requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise { // tslint:disable-line:no-any return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options); diff --git a/packages/core/test/WorkflowExecute.test.ts b/packages/core/test/WorkflowExecute.test.ts index 454dd521b5..2bbdb83be8 100644 --- a/packages/core/test/WorkflowExecute.test.ts +++ b/packages/core/test/WorkflowExecute.test.ts @@ -1348,7 +1348,7 @@ describe('WorkflowExecute', () => { const workflowExecute = new WorkflowExecute(additionalData, executionMode); - const executionData = await workflowExecute.run(workflowInstance, undefined); + const executionData = await workflowExecute.run(workflowInstance); const result = await waitPromise.promise(); diff --git a/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts b/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts index 65cc1f3c1c..a58e122f12 100644 --- a/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts +++ b/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts @@ -13,7 +13,6 @@ import { } from 'xml2js'; import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -607,8 +606,9 @@ export class AwsS3 implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); - body = Buffer.from(binaryData.data, BINARY_ENCODING) as Buffer; + body = binaryDataBuffer; headers['Content-Type'] = binaryData.mimeType; diff --git a/packages/nodes-base/nodes/Box/Box.node.ts b/packages/nodes-base/nodes/Box/Box.node.ts index 00d19f596e..b5a6ab529f 100644 --- a/packages/nodes-base/nodes/Box/Box.node.ts +++ b/packages/nodes-base/nodes/Box/Box.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -277,6 +276,7 @@ export class Box implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); const body: IDataObject = {}; @@ -285,7 +285,7 @@ export class Box implements INodeType { body['attributes'] = JSON.stringify(attributes); body['file'] = { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: binaryDataBuffer, options: { filename: binaryData.fileName, contentType: binaryData.mimeType, diff --git a/packages/nodes-base/nodes/Cisco/Webex/CiscoWebex.node.ts b/packages/nodes-base/nodes/Cisco/Webex/CiscoWebex.node.ts index 430f69cfd6..80cb3c71f2 100644 --- a/packages/nodes-base/nodes/Cisco/Webex/CiscoWebex.node.ts +++ b/packages/nodes-base/nodes/Cisco/Webex/CiscoWebex.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -174,10 +173,11 @@ export class CiscoWebex implements INodeType { const binaryPropertyName = file.binaryPropertyName as string; const binaryData = items[i].binary![binaryPropertyName] as IBinaryData; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); const formData = { files: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: binaryDataBuffer, options: { filename: binaryData.fileName, contentType: binaryData.mimeType, diff --git a/packages/nodes-base/nodes/Compression.node.ts b/packages/nodes-base/nodes/Compression.node.ts index 14cbdd5008..bb8d6ab45c 100644 --- a/packages/nodes-base/nodes/Compression.node.ts +++ b/packages/nodes-base/nodes/Compression.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -226,9 +225,10 @@ export class Compression implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); if (binaryData.fileExtension === 'zip') { - const files = await unzip(Buffer.from(binaryData.data as string, BINARY_ENCODING)); + const files = await unzip(binaryDataBuffer); for (const key of Object.keys(files)) { // when files are compresed using MACOSX for some reason they are duplicated under __MACOSX @@ -241,7 +241,7 @@ export class Compression implements INodeType { binaryObject[`${outputPrefix}${zipIndex++}`] = data; } } else if (binaryData.fileExtension === 'gz') { - const file = await gunzip(Buffer.from(binaryData.data as string, BINARY_ENCODING)); + const file = await gunzip(binaryDataBuffer); const fileName = binaryData.fileName?.split('.')[0]; @@ -280,10 +280,11 @@ export class Compression implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); if (outputFormat === 'zip') { zipData[binaryData.fileName as string] = [ - Buffer.from(binaryData.data, BINARY_ENCODING), { + binaryDataBuffer, { level: ALREADY_COMPRESSED.includes(binaryData.fileExtension as string) ? 0 : 6, }, ]; @@ -291,7 +292,7 @@ export class Compression implements INodeType { } else if (outputFormat === 'gzip') { const outputPrefix = this.getNodeParameter('outputPrefix', 0) as string; - const data = await gzip(Buffer.from(binaryData.data, BINARY_ENCODING)) as Uint8Array; + const data = await gzip(binaryDataBuffer) as Uint8Array; const fileName = binaryData.fileName?.split('.')[0]; @@ -323,10 +324,10 @@ export class Compression implements INodeType { }); } } - + } catch (error) { if (this.continueOnFail()) { - returnData.push({json:{ error: error.message }}); + returnData.push({ json: { error: error.message } }); continue; } throw error; diff --git a/packages/nodes-base/nodes/HumanticAI/HumanticAi.node.ts b/packages/nodes-base/nodes/HumanticAI/HumanticAi.node.ts index d72598be51..9fd8d8a3a9 100644 --- a/packages/nodes-base/nodes/HumanticAI/HumanticAi.node.ts +++ b/packages/nodes-base/nodes/HumanticAI/HumanticAi.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -88,6 +87,7 @@ export class HumanticAi implements INodeType { const item = items[i].binary as IBinaryKeyData; const binaryData = item[binaryPropertyName] as IBinaryData; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); if (binaryData === undefined) { throw new NodeOperationError(this.getNode(), `No binary data property "${binaryPropertyName}" does not exists on item!`); @@ -102,7 +102,7 @@ export class HumanticAi implements INodeType { { formData: { resume: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: binaryDataBuffer, options: { filename: binaryData.fileName, }, @@ -148,6 +148,7 @@ export class HumanticAi implements INodeType { const item = items[i].binary as IBinaryKeyData; const binaryData = item[binaryPropertyName] as IBinaryData; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); if (binaryData === undefined) { throw new NodeOperationError(this.getNode(), `No binary data property "${binaryPropertyName}" does not exists on item!`); @@ -162,7 +163,7 @@ export class HumanticAi implements INodeType { { formData: { resume: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: binaryDataBuffer, options: { filename: binaryData.fileName, }, diff --git a/packages/nodes-base/nodes/Jira/Jira.node.ts b/packages/nodes-base/nodes/Jira/Jira.node.ts index 1f26a3e5ff..0f844630a8 100644 --- a/packages/nodes-base/nodes/Jira/Jira.node.ts +++ b/packages/nodes-base/nodes/Jira/Jira.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -754,6 +753,7 @@ export class Jira implements INodeType { const item = items[i].binary as IBinaryKeyData; const binaryData = item[binaryPropertyName] as IBinaryData; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); if (binaryData === undefined) { throw new NodeOperationError(this.getNode(), `No binary data property "${binaryPropertyName}" does not exists on item!`); @@ -769,7 +769,7 @@ export class Jira implements INodeType { { formData: { file: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: binaryDataBuffer, options: { filename: binaryData.fileName, }, diff --git a/packages/nodes-base/nodes/Line/Line.node.ts b/packages/nodes-base/nodes/Line/Line.node.ts index 2b2deac3ab..f7e84c2daa 100644 --- a/packages/nodes-base/nodes/Line/Line.node.ts +++ b/packages/nodes-base/nodes/Line/Line.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -118,9 +117,10 @@ export class Line implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[image.binaryProperty as string]; + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, image.binaryProperty as string); body.imageFile = { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: binaryDataBuffer, options: { filename: binaryData.fileName, }, diff --git a/packages/nodes-base/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.ts b/packages/nodes-base/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.ts index 052450eae9..da16900725 100644 --- a/packages/nodes-base/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.ts +++ b/packages/nodes-base/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -192,8 +191,8 @@ export class MicrosoftOneDrive implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; + const body = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); - const body = Buffer.from(binaryData.data, BINARY_ENCODING); responseData = await microsoftApiRequest.call(this, 'PUT', `/drive/items/${parentId}:/${fileName || binaryData.fileName}:/content`, body, {}, undefined, { 'Content-Type': binaryData.mimeType, 'Content-length': body.length }, {} ); returnData.push(JSON.parse(responseData) as IDataObject); diff --git a/packages/nodes-base/nodes/Microsoft/Outlook/MicrosoftOutlook.node.ts b/packages/nodes-base/nodes/Microsoft/Outlook/MicrosoftOutlook.node.ts index 86cf504b15..4a47128c88 100644 --- a/packages/nodes-base/nodes/Microsoft/Outlook/MicrosoftOutlook.node.ts +++ b/packages/nodes-base/nodes/Microsoft/Outlook/MicrosoftOutlook.node.ts @@ -648,7 +648,7 @@ export class MicrosoftOutlook implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; - const dataBuffer = Buffer.from(binaryData.data, 'base64'); + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); const fileName = additionalFields.fileName === undefined ? binaryData.fileName : additionalFields.fileName; diff --git a/packages/nodes-base/nodes/Mindee/Mindee.node.ts b/packages/nodes-base/nodes/Mindee/Mindee.node.ts index 2b23ee27ff..d6e437a364 100644 --- a/packages/nodes-base/nodes/Mindee/Mindee.node.ts +++ b/packages/nodes-base/nodes/Mindee/Mindee.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -140,6 +139,7 @@ export class Mindee implements INodeType { const item = items[i].binary as IBinaryKeyData; const binaryData = item[binaryPropertyName] as IBinaryData; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); if (binaryData === undefined) { throw new NodeOperationError(this.getNode(), `No binary data property "${binaryPropertyName}" does not exists on item!`); @@ -154,7 +154,7 @@ export class Mindee implements INodeType { { formData: { file: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, @@ -182,6 +182,7 @@ export class Mindee implements INodeType { const item = items[i].binary as IBinaryKeyData; const binaryData = item[binaryPropertyName] as IBinaryData; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); if (binaryData === undefined) { throw new NodeOperationError(this.getNode(), `No binary data property "${binaryPropertyName}" does not exists on item!`); @@ -196,7 +197,7 @@ export class Mindee implements INodeType { { formData: { file: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, diff --git a/packages/nodes-base/nodes/NocoDB/NocoDB.node.ts b/packages/nodes-base/nodes/NocoDB/NocoDB.node.ts index a32eb12db8..f42ab38ea0 100644 --- a/packages/nodes-base/nodes/NocoDB/NocoDB.node.ts +++ b/packages/nodes-base/nodes/NocoDB/NocoDB.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -160,10 +159,11 @@ export class NocoDB implements INodeType { throw new NodeOperationError(this.getNode(), `Binary property ${binaryPropertyName} does not exist on item!`); } const binaryData = items[i].binary![binaryPropertyName] as IBinaryData; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); const formData = { file: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, contentType: binaryData.mimeType, @@ -338,10 +338,11 @@ export class NocoDB implements INodeType { throw new NodeOperationError(this.getNode(), `Binary property ${binaryPropertyName} does not exist on item!`); } const binaryData = items[i].binary![binaryPropertyName] as IBinaryData; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); const formData = { file: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, contentType: binaryData.mimeType, diff --git a/packages/nodes-base/nodes/Pushbullet/Pushbullet.node.ts b/packages/nodes-base/nodes/Pushbullet/Pushbullet.node.ts index 718a5f8a5b..1e57ab093c 100644 --- a/packages/nodes-base/nodes/Pushbullet/Pushbullet.node.ts +++ b/packages/nodes-base/nodes/Pushbullet/Pushbullet.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -495,6 +494,7 @@ export class Pushbullet implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); //create upload url const { @@ -523,7 +523,7 @@ export class Pushbullet implements INodeType { { formData: { file: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, diff --git a/packages/nodes-base/nodes/Pushover/Pushover.node.ts b/packages/nodes-base/nodes/Pushover/Pushover.node.ts index b6b56f1459..deea02da99 100644 --- a/packages/nodes-base/nodes/Pushover/Pushover.node.ts +++ b/packages/nodes-base/nodes/Pushover/Pushover.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -366,8 +365,10 @@ export class Pushover implements INodeType { throw new NodeOperationError(this.getNode(), `No binary data property "${binaryPropertyName}" does not exists on item!`); } + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); + body.attachment = { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, diff --git a/packages/nodes-base/nodes/Raindrop/Raindrop.node.ts b/packages/nodes-base/nodes/Raindrop/Raindrop.node.ts index 036d3e8649..d208ef0093 100644 --- a/packages/nodes-base/nodes/Raindrop/Raindrop.node.ts +++ b/packages/nodes-base/nodes/Raindrop/Raindrop.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -345,10 +344,11 @@ export class Raindrop implements INodeType { const binaryPropertyName = updateFields.cover as string; const binaryData = items[i].binary![binaryPropertyName] as IBinaryData; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); const formData = { cover: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, contentType: binaryData.mimeType, diff --git a/packages/nodes-base/nodes/S3/S3.node.ts b/packages/nodes-base/nodes/S3/S3.node.ts index 4b44ff810e..f9cdb0e2a8 100644 --- a/packages/nodes-base/nodes/S3/S3.node.ts +++ b/packages/nodes-base/nodes/S3/S3.node.ts @@ -1,4 +1,3 @@ - import { paramCase, snakeCase, @@ -608,8 +607,7 @@ export class S3 implements INodeType { } const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; - - body = Buffer.from(binaryData.data, BINARY_ENCODING) as Buffer; + body = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); headers['Content-Type'] = binaryData.mimeType; diff --git a/packages/nodes-base/nodes/Salesforce/Salesforce.node.ts b/packages/nodes-base/nodes/Salesforce/Salesforce.node.ts index b8a61e32f6..4c7f45db7e 100644 --- a/packages/nodes-base/nodes/Salesforce/Salesforce.node.ts +++ b/packages/nodes-base/nodes/Salesforce/Salesforce.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -1686,6 +1685,8 @@ export class Salesforce implements INodeType { } if (items[i].binary && items[i].binary![binaryPropertyName]) { const binaryData = items[i].binary![binaryPropertyName]; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); + body.entity_content['PathOnClient'] = `${title}.${binaryData.fileExtension}`; data = { entity_content: { @@ -1695,7 +1696,7 @@ export class Salesforce implements INodeType { }, }, VersionData: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, contentType: binaryData.mimeType, diff --git a/packages/nodes-base/nodes/Ssh/Ssh.node.ts b/packages/nodes-base/nodes/Ssh/Ssh.node.ts index 3a3ed5fb30..b136752527 100644 --- a/packages/nodes-base/nodes/Ssh/Ssh.node.ts +++ b/packages/nodes-base/nodes/Ssh/Ssh.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -389,9 +388,11 @@ export class Ssh implements INodeType { throw new Error(`No binary data property "${propertyNameUpload}" does not exists on item!`); } + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, propertyNameUpload); + const { path } = await file({ prefix: 'n8n-ssh-' }); temporaryFiles.push(path); - await writeFile(path, Buffer.from(binaryData.data, BINARY_ENCODING)); + await writeFile(path, dataBuffer); await ssh.putFile(path, `${parameterPath}${(parameterPath.charAt(parameterPath.length - 1) === '/') ? '' : '/'}${fileName || binaryData.fileName}`); diff --git a/packages/nodes-base/nodes/TheHive/TheHive.node.ts b/packages/nodes-base/nodes/TheHive/TheHive.node.ts index 554b22dd20..62894dae66 100644 --- a/packages/nodes-base/nodes/TheHive/TheHive.node.ts +++ b/packages/nodes-base/nodes/TheHive/TheHive.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions } from 'n8n-core'; @@ -929,11 +928,12 @@ export class TheHive implements INodeType { } const binaryData = item.binary[binaryPropertyName] as IBinaryData; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); options = { formData: { attachment: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { contentType: binaryData.mimeType, filename: binaryData.fileName, @@ -1885,11 +1885,12 @@ export class TheHive implements INodeType { } const binaryData = item.binary[binaryPropertyName] as IBinaryData; + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); options = { formData: { attachment: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { contentType: binaryData.mimeType, filename: binaryData.fileName, diff --git a/packages/nodes-base/nodes/Twist/Twist.node.ts b/packages/nodes-base/nodes/Twist/Twist.node.ts index c749e2b577..647dd54812 100644 --- a/packages/nodes-base/nodes/Twist/Twist.node.ts +++ b/packages/nodes-base/nodes/Twist/Twist.node.ts @@ -1,5 +1,4 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; @@ -278,6 +277,8 @@ export class Twist implements INodeType { throw new Error(`No binary data property "${binaryProperty}" does not exists on item!`); } + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty); + attachments.push(await twistApiRequest.call( this, 'POST', @@ -287,7 +288,7 @@ export class Twist implements INodeType { { formData: { file_name: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, @@ -380,6 +381,8 @@ export class Twist implements INodeType { throw new Error(`No binary data property "${binaryProperty}" does not exists on item!`); } + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty); + attachments.push(await twistApiRequest.call( this, 'POST', @@ -389,7 +392,7 @@ export class Twist implements INodeType { { formData: { file_name: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, @@ -452,6 +455,8 @@ export class Twist implements INodeType { throw new NodeOperationError(this.getNode(), `No binary data property "${binaryProperty}" does not exists on item!`); } + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty); + attachments.push(await twistApiRequest.call( this, 'POST', @@ -461,7 +466,7 @@ export class Twist implements INodeType { { formData: { file_name: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, @@ -547,6 +552,8 @@ export class Twist implements INodeType { throw new Error(`No binary data property "${binaryProperty}" does not exists on item!`); } + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty); + attachments.push(await twistApiRequest.call( this, 'POST', @@ -556,7 +563,7 @@ export class Twist implements INodeType { { formData: { file_name: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, @@ -619,6 +626,8 @@ export class Twist implements INodeType { throw new Error(`No binary data property "${binaryProperty}" does not exists on item!`); } + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty); + attachments.push(await twistApiRequest.call( this, 'POST', @@ -628,7 +637,7 @@ export class Twist implements INodeType { { formData: { file_name: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, @@ -720,6 +729,8 @@ export class Twist implements INodeType { throw new Error(`No binary data property "${binaryProperty}" does not exists on item!`); } + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty); + attachments.push(await twistApiRequest.call( this, 'POST', @@ -729,7 +740,7 @@ export class Twist implements INodeType { { formData: { file_name: { - value: Buffer.from(binaryData.data, BINARY_ENCODING), + value: dataBuffer, options: { filename: binaryData.fileName, }, diff --git a/packages/nodes-base/nodes/Twitter/GenericFunctions.ts b/packages/nodes-base/nodes/Twitter/GenericFunctions.ts index 260f2ac3ca..9df93ced2b 100644 --- a/packages/nodes-base/nodes/Twitter/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Twitter/GenericFunctions.ts @@ -3,7 +3,6 @@ import { } from 'request'; import { - BINARY_ENCODING, IExecuteFunctions, IExecuteSingleFunctions, IHookFunctions, @@ -96,7 +95,8 @@ export async function uploadAttachments(this: IExecuteFunctions, binaryPropertie let attachmentBody = {}; let response: IDataObject = {}; - const isAnimatedWebp = (Buffer.from(binaryData[binaryPropertyName].data, 'base64').toString().indexOf('ANMF') !== -1); + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); + const isAnimatedWebp = (dataBuffer.toString().indexOf('ANMF') !== -1); const isImage = binaryData[binaryPropertyName].mimeType.includes('image'); @@ -118,9 +118,11 @@ export async function uploadAttachments(this: IExecuteFunctions, binaryPropertie // https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-init + const dataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); + attachmentBody = { command: 'INIT', - total_bytes: Buffer.from(binaryData[binaryPropertyName].data, BINARY_ENCODING).byteLength, + total_bytes: dataBuffer.byteLength, media_type: binaryData[binaryPropertyName].mimeType, }; @@ -130,7 +132,7 @@ export async function uploadAttachments(this: IExecuteFunctions, binaryPropertie // break the data on 5mb chunks (max size that can be uploaded at once) - const binaryParts = chunks(Buffer.from(binaryData[binaryPropertyName].data, BINARY_ENCODING), 5242880); + const binaryParts = chunks(dataBuffer, 5242880); let index = 0; diff --git a/packages/nodes-base/nodes/WriteBinaryFile.node.ts b/packages/nodes-base/nodes/WriteBinaryFile.node.ts index db1b6371ed..a9e52696c6 100644 --- a/packages/nodes-base/nodes/WriteBinaryFile.node.ts +++ b/packages/nodes-base/nodes/WriteBinaryFile.node.ts @@ -1,7 +1,5 @@ import { - BINARY_ENCODING, IExecuteFunctions, - IExecuteSingleFunctions } from 'n8n-core'; import { IDataObject, @@ -76,14 +74,16 @@ export class WriteBinaryFile implements INodeType { throw new NodeOperationError(this.getNode(), `The binary property "${dataPropertyName}" does not exist. So no file can be written!`); } - // Write the file to disk - await fsWriteFile(fileName, Buffer.from(item.binary[dataPropertyName].data, BINARY_ENCODING), 'binary'); - const newItem: INodeExecutionData = { json: {}, }; Object.assign(newItem.json, item.json); + const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(itemIndex, dataPropertyName); + + // Write the file to disk + await fsWriteFile(fileName, binaryDataBuffer, 'binary'); + if (item.binary !== undefined) { // Create a shallow copy of the binary data so that the old // data references which do not get changed still stay behind @@ -100,7 +100,7 @@ export class WriteBinaryFile implements INodeType { } catch (error) { if (this.continueOnFail()) { - returnData.push({json:{ error: error.message }}); + returnData.push({ json: { error: error.message } }); continue; } throw error; From 7ce7285f7a80e3bfd86ceac4fb632ccd71ad60ef Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Fri, 20 Aug 2021 18:57:30 +0200 Subject: [PATCH 06/30] :zap: Load credentials from the database (#1741) * Changes to types so that credentials can be always loaded from DB This first commit changes all return types from the execute functions and calls to get credentials to be async so we can use await. This is a first step as previously credentials were loaded in memory and always available. We will now be loading them from the DB which requires turning the whole call chain async. * Fix updated files * Removed unnecessary credential loading to improve performance * Fix typo * :zap: Fix issue * Updated new nodes to load credentials async * :zap: Remove not needed comment Co-authored-by: Jan Oberhauser --- packages/cli/commands/execute.ts | 3 -- packages/cli/commands/executeBatch.ts | 2 - packages/cli/commands/worker.ts | 4 +- packages/cli/src/ActiveWorkflowRunner.ts | 11 ++-- packages/cli/src/CredentialsHelper.ts | 21 +++++--- packages/cli/src/Interfaces.ts | 1 - packages/cli/src/Server.ts | 48 +++++------------ packages/cli/src/WebhookHelpers.ts | 4 +- .../cli/src/WorkflowExecuteAdditionalData.ts | 16 ++---- packages/cli/src/WorkflowHelpers.ts | 3 -- packages/cli/src/WorkflowRunner.ts | 41 +++------------ packages/cli/src/WorkflowRunnerProcess.ts | 19 +++++-- packages/core/src/NodeExecuteFunctions.ts | 40 +++++++-------- packages/core/test/Helpers.ts | 13 ++--- .../nodes/ActionNetwork/GenericFunctions.ts | 2 +- .../nodes/ActiveCampaign/GenericFunctions.ts | 2 +- .../AcuityScheduling/GenericFunctions.ts | 2 +- .../nodes/Affinity/GenericFunctions.ts | 2 +- .../nodes/AgileCrm/GenericFunctions.ts | 4 +- .../nodes/Airtable/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Amqp/Amqp.node.ts | 2 +- .../nodes-base/nodes/Amqp/AmqpTrigger.node.ts | 2 +- .../nodes/ApiTemplateIo/GenericFunctions.ts | 2 +- .../nodes/Asana/GenericFunctions.ts | 2 +- .../nodes/Automizy/GenericFunctions.ts | 2 +- .../nodes/Autopilot/GenericFunctions.ts | 2 +- .../nodes/Aws/Comprehend/GenericFunctions.ts | 2 +- .../nodes/Aws/DynamoDB/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Aws/GenericFunctions.ts | 2 +- .../nodes/Aws/Rekognition/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Aws/S3/AwsS3.node.ts | 2 +- .../nodes/Aws/S3/GenericFunctions.ts | 2 +- .../nodes/Aws/SES/GenericFunctions.ts | 2 +- .../nodes/Aws/Transcribe/GenericFunctions.ts | 2 +- .../nodes/Bannerbear/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Baserow/Baserow.node.ts | 8 +-- .../nodes/Baserow/GenericFunctions.ts | 2 +- .../Beeminder/Beeminder.node.functions.ts | 8 +-- .../nodes/Beeminder/Beeminder.node.ts | 2 +- .../nodes/Beeminder/GenericFunctions.ts | 2 +- .../nodes/Bitbucket/BitbucketTrigger.node.ts | 8 +-- .../nodes/Bitbucket/GenericFunctions.ts | 2 +- .../nodes/Bitly/GenericFunctions.ts | 2 +- .../nodes/Bitwarden/GenericFunctions.ts | 15 +++--- .../nodes/Brandfetch/GenericFunctions.ts | 2 +- .../nodes/Bubble/GenericFunctions.ts | 2 +- .../nodes/Calendly/GenericFunctions.ts | 2 +- .../nodes/Chargebee/Chargebee.node.ts | 2 +- .../nodes/CircleCi/GenericFunctions.ts | 2 +- .../Cisco/Webex/CiscoWebexTrigger.node.ts | 7 ++- .../nodes/Clearbit/GenericFunctions.ts | 2 +- .../nodes/ClickUp/GenericFunctions.ts | 2 +- .../nodes/Clockify/GenericFunctions.ts | 2 +- .../nodes/Cockpit/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Coda/GenericFunctions.ts | 2 +- .../nodes/Contentful/Contentful.node.ts | 14 ++--- .../nodes/Contentful/GenericFunctions.ts | 2 +- .../nodes/ConvertKit/GenericFunctions.ts | 2 +- .../nodes/Copper/CopperTrigger.node.ts | 4 +- .../nodes/Copper/GenericFunctions.ts | 2 +- .../nodes/Cortex/GenericFunctions.ts | 2 +- .../nodes-base/nodes/CrateDb/CrateDb.node.ts | 2 +- .../nodes/CustomerIo/GenericFunctions.ts | 2 +- .../nodes/DeepL/GenericFunctions.ts | 8 ++- .../nodes/Demio/GenericFunctions.ts | 2 +- .../nodes/Discourse/GenericFunctions.ts | 2 +- .../nodes/Disqus/GenericFunctions.ts | 2 +- .../nodes/Drift/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Dropbox/Dropbox.node.ts | 2 +- .../nodes/Dropbox/GenericFunctions.ts | 8 +-- .../nodes/ERPNext/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Egoi/GenericFunctions.ts | 2 +- .../nodes/Elasticsearch/GenericFunctions.ts | 2 +- .../nodes-base/nodes/EmailReadImap.node.ts | 2 +- packages/nodes-base/nodes/EmailSend.node.ts | 2 +- .../nodes/Emelia/GenericFunctions.ts | 2 +- .../nodes/Eventbrite/GenericFunctions.ts | 2 +- .../nodes/Facebook/FacebookGraphApi.node.ts | 2 +- .../nodes/Facebook/FacebookTrigger.node.ts | 2 +- .../nodes/Facebook/GenericFunctions.ts | 4 +- .../nodes/FileMaker/FileMaker.node.ts | 2 +- .../nodes/FileMaker/GenericFunctions.ts | 12 ++--- packages/nodes-base/nodes/Flow/Flow.node.ts | 2 +- .../nodes-base/nodes/Flow/FlowTrigger.node.ts | 6 +-- .../nodes-base/nodes/Flow/GenericFunctions.ts | 2 +- .../nodes/Freshdesk/GenericFunctions.ts | 2 +- .../nodes/FreshworksCrm/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Ftp.node.ts | 4 +- .../nodes/GetResponse/GenericFunctions.ts | 2 +- .../nodes/Ghost/GenericFunctions.ts | 4 +- packages/nodes-base/nodes/Git/Git.node.ts | 10 ++-- .../nodes/Github/GenericFunctions.ts | 4 +- .../nodes/Gitlab/GenericFunctions.ts | 4 +- .../nodes-base/nodes/Gitlab/Gitlab.node.ts | 4 +- .../nodes/GoToWebinar/GenericFunctions.ts | 10 ++-- .../nodes/GoToWebinar/GoToWebinar.node.ts | 2 +- .../nodes/Google/Books/GenericFunctions.ts | 2 +- .../nodes/Google/Docs/GenericFunctions.ts | 2 +- .../nodes/Google/Drive/GenericFunctions.ts | 2 +- .../Google/Drive/GoogleDriveTrigger.node.ts | 4 +- .../nodes/Google/Gmail/GenericFunctions.ts | 2 +- .../nodes/Google/Sheet/GenericFunctions.ts | 2 +- .../nodes/Google/Slides/GenericFunctions.ts | 2 +- .../Google/Translate/GenericFunctions.ts | 2 +- .../nodes/Gotify/GenericFunctions.ts | 2 +- .../nodes-base/nodes/GraphQL/GraphQL.node.ts | 2 +- .../nodes/Gumroad/GenericFunctions.ts | 2 +- .../nodes/Harvest/GenericFunctions.ts | 2 +- .../nodes/HomeAssistant/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/HttpRequest.node.ts | 10 ++-- .../nodes/Hubspot/GenericFunctions.ts | 4 +- .../nodes/Hubspot/HubspotTrigger.node.ts | 8 +-- .../nodes/HumanticAI/GenericFunctions.ts | 2 +- .../nodes/Hunter/GenericFunctions.ts | 2 +- .../nodes/Intercom/GenericFunctions.ts | 2 +- .../nodes/InvoiceNinja/GenericFunctions.ts | 2 +- .../nodes/Iterable/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Jira/GenericFunctions.ts | 4 +- .../nodes/JotForm/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Kafka/Kafka.node.ts | 2 +- .../nodes/Kafka/KafkaTrigger.node.ts | 2 +- .../nodes/Kitemaker/GenericFunctions.ts | 2 +- .../nodes/Lemlist/GenericFunctions.ts | 2 +- .../nodes/LingvaNex/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/MQTT/Mqtt.node.ts | 2 +- .../nodes-base/nodes/MQTT/MqttTrigger.node.ts | 2 +- .../nodes/Mailcheck/GenericFunctions.ts | 2 +- .../nodes/Mailchimp/GenericFunctions.ts | 8 +-- .../nodes/MailerLite/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Mailgun/Mailgun.node.ts | 2 +- .../nodes/Mailjet/GenericFunctions.ts | 4 +- .../nodes/Mandrill/GenericFunctions.ts | 2 +- .../nodes/Marketstack/GenericFunctions.ts | 2 +- .../nodes/Matrix/GenericFunctions.ts | 2 +- .../nodes/Mattermost/GenericFunctions.ts | 2 +- .../nodes/Mattermost/Mattermost.node.ts | 2 +- .../nodes/Mautic/GenericFunctions.ts | 4 +- .../nodes/Medium/GenericFunctions.ts | 2 +- .../nodes/MessageBird/GenericFunctions.ts | 2 +- .../Microsoft/Outlook/GenericFunctions.ts | 2 +- .../nodes/Microsoft/Sql/MicrosoftSql.node.ts | 2 +- .../nodes/Mindee/GenericFunctions.ts | 4 +- .../nodes/Mocean/GenericFunctions.ts | 2 +- .../nodes/MondayCom/GenericFunctions.ts | 2 +- .../nodes-base/nodes/MongoDb/MongoDb.node.ts | 2 +- .../nodes/MonicaCrm/GenericFunctions.ts | 2 +- .../nodes/Msg91/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/MySql/MySql.node.ts | 2 +- .../nodes-base/nodes/Nasa/GenericFunctions.ts | 2 +- .../nodes/NextCloud/GenericFunctions.ts | 4 +- .../nodes/NextCloud/NextCloud.node.ts | 4 +- .../nodes/NocoDB/GenericFunctions.ts | 2 +- .../nodes/Notion/GenericFunctions.ts | 2 +- .../nodes-base/nodes/OpenWeatherMap.node.ts | 2 +- .../nodes/Orbit/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Oura/GenericFunctions.ts | 2 +- .../nodes/Paddle/GenericFunctions.ts | 2 +- .../nodes/PagerDuty/GenericFunctions.ts | 2 +- .../nodes/PayPal/GenericFunctions.ts | 4 +- .../nodes/Peekalink/GenericFunctions.ts | 2 +- .../nodes/Phantombuster/GenericFunctions.ts | 2 +- .../nodes/Pipedrive/GenericFunctions.ts | 2 +- .../nodes/Pipedrive/PipedriveTrigger.node.ts | 4 +- .../nodes/Plivo/GenericFunctions.ts | 2 +- .../nodes/PostHog/GenericFunctions.ts | 2 +- .../nodes/Postgres/Postgres.node.ts | 2 +- .../nodes/Postmark/GenericFunctions.ts | 2 +- .../nodes/ProfitWell/GenericFunctions.ts | 2 +- .../nodes/Pushcut/GenericFunctions.ts | 2 +- .../nodes/Pushover/GenericFunctions.ts | 2 +- .../nodes-base/nodes/QuestDb/QuestDb.node.ts | 2 +- .../nodes/QuickBase/GenericFunctions.ts | 2 +- .../nodes/QuickBooks/GenericFunctions.ts | 4 +- .../nodes/QuickBooks/QuickBooks.node.ts | 3 +- .../nodes/RabbitMQ/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Redis/Redis.node.ts | 4 +- .../nodes/Rocketchat/GenericFunctions.ts | 2 +- .../nodes-base/nodes/S3/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/S3/S3.node.ts | 2 +- .../nodes/Salesforce/GenericFunctions.ts | 4 +- .../nodes/Salesmate/GenericFunctions.ts | 2 +- .../SecurityScorecard/GenericFunctions.ts | 2 +- .../nodes/Segment/GenericFunctions.ts | 2 +- .../nodes/SendGrid/GenericFunctions.ts | 2 +- .../nodes/Sendy/GenericFunctions.ts | 2 +- .../nodes/SentryIo/GenericFunctions.ts | 2 +- .../nodes/ServiceNow/GenericFunctions.ts | 2 +- .../nodes/Shopify/GenericFunctions.ts | 2 +- .../nodes/Shopify/ShopifyTrigger.node.ts | 2 +- .../nodes/Signl4/GenericFunctions.ts | 2 +- .../nodes/Slack/GenericFunctions.ts | 2 +- .../nodes/Sms77/GenericFunctions.ts | 2 +- .../nodes/Snowflake/Snowflake.node.ts | 2 +- .../nodes/Spontit/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Ssh/Ssh.node.ts | 4 +- .../nodes/Stackby/GenericFunction.ts | 2 +- .../nodes/Storyblok/GenericFunctions.ts | 4 +- .../nodes/Strapi/GenericFunctions.ts | 4 +- .../nodes/Strava/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Stripe/helpers.ts | 2 +- .../nodes/SurveyMonkey/GenericFunctions.ts | 2 +- .../SurveyMonkey/SurveyMonkeyTrigger.node.ts | 4 +- .../nodes/Taiga/GenericFunctions.ts | 2 +- .../nodes/Taiga/TaigaTrigger.node.ts | 2 +- .../nodes/Tapfiliate/GenericFunctions.ts | 2 +- .../nodes/Telegram/GenericFunctions.ts | 2 +- .../nodes/Telegram/Telegram.node.ts | 2 +- .../nodes/Telegram/TelegramTrigger.node.ts | 2 +- .../nodes/TheHive/GenericFunctions.ts | 8 ++- .../nodes-base/nodes/TheHive/TheHive.node.ts | 51 ++++++++++++------- .../nodes/TimescaleDb/TimescaleDb.node.ts | 2 +- .../nodes/Todoist/GenericFunctions.ts | 2 +- .../nodes/Toggl/GenericFunctions.ts | 2 +- .../nodes/TravisCi/GenericFunctions.ts | 2 +- .../nodes/Trello/GenericFunctions.ts | 2 +- .../nodes/Trello/TrelloTrigger.node.ts | 8 +-- .../nodes/Twake/GenericFunctions.ts | 4 +- .../nodes/Twilio/GenericFunctions.ts | 2 +- .../nodes/Typeform/GenericFunctions.ts | 2 +- .../nodes/UProc/GenericFunctions.ts | 2 +- .../UnleashedSoftware/GenericFunctions.ts | 2 +- .../nodes/Uplead/GenericFunctions.ts | 2 +- .../nodes/UptimeRobot/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Vero/GenericFunctions.ts | 2 +- .../nodes/Vonage/GenericFunctions.ts | 2 +- .../nodes/Webflow/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Webhook.node.ts | 4 +- .../nodes/Wekan/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Wise/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Wise/Wise.node.ts | 2 +- .../nodes-base/nodes/Wise/WiseTrigger.node.ts | 2 +- .../nodes/WooCommerce/GenericFunctions.ts | 2 +- .../WooCommerce/WooCommerceTrigger.node.ts | 2 +- .../nodes/Wordpress/GenericFunctions.ts | 2 +- .../nodes/Wufoo/GenericFunctions.ts | 2 +- .../nodes/Yourls/GenericFunctions.ts | 2 +- .../nodes/Zendesk/GenericFunctions.ts | 4 +- .../nodes-base/nodes/Zoho/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Zoom/GenericFunctions.ts | 2 +- .../nodes/Zulip/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Zulip/Zulip.node.ts | 2 +- packages/workflow/src/Interfaces.ts | 23 ++++----- 242 files changed, 450 insertions(+), 481 deletions(-) diff --git a/packages/cli/commands/execute.ts b/packages/cli/commands/execute.ts index 48ae6a19f0..662d372023 100644 --- a/packages/cli/commands/execute.ts +++ b/packages/cli/commands/execute.ts @@ -155,10 +155,7 @@ export class Execute extends Command { } try { - const credentials = await WorkflowCredentials(workflowData!.nodes); - const runData: IWorkflowExecutionDataProcess = { - credentials, executionMode: 'cli', startNodes: [startNode.name], workflowData: workflowData!, diff --git a/packages/cli/commands/executeBatch.ts b/packages/cli/commands/executeBatch.ts index dc5f4030db..b1022c6561 100644 --- a/packages/cli/commands/executeBatch.ts +++ b/packages/cli/commands/executeBatch.ts @@ -635,10 +635,8 @@ export class ExecuteBatch extends Command { try { - const credentials = await WorkflowCredentials(workflowData!.nodes); const runData: IWorkflowExecutionDataProcess = { - credentials, executionMode: 'cli', startNodes: [startNode!.name], workflowData: workflowData!, diff --git a/packages/cli/commands/worker.ts b/packages/cli/commands/worker.ts index 56da5d9c98..b5ce727ceb 100644 --- a/packages/cli/commands/worker.ts +++ b/packages/cli/commands/worker.ts @@ -148,9 +148,7 @@ export class Worker extends Command { const workflow = new Workflow({ id: currentExecutionDb.workflowData.id as string, name: currentExecutionDb.workflowData.name, nodes: currentExecutionDb.workflowData!.nodes, connections: currentExecutionDb.workflowData!.connections, active: currentExecutionDb.workflowData!.active, nodeTypes, staticData, settings: currentExecutionDb.workflowData!.settings }); - const credentials = await WorkflowCredentials(currentExecutionDb.workflowData.nodes); - - const additionalData = await WorkflowExecuteAdditionalData.getBase(credentials, undefined, executionTimeoutTimestamp); + const additionalData = await WorkflowExecuteAdditionalData.getBase(undefined, executionTimeoutTimestamp); additionalData.hooks = WorkflowExecuteAdditionalData.getWorkflowHooksWorkerExecuter(currentExecutionDb.mode, job.data.executionId, currentExecutionDb.workflowData, { retryOf: currentExecutionDb.retryOf as string }); let workflowExecute: WorkflowExecute; diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index be77bd101f..ee48be8dd7 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -192,9 +192,7 @@ export class ActiveWorkflowRunner { const nodeTypes = NodeTypes(); const workflow = new Workflow({ id: webhook.workflowId.toString(), name: workflowData.name, nodes: workflowData.nodes, connections: workflowData.connections, active: workflowData.active, nodeTypes, staticData: workflowData.staticData, settings: workflowData.settings }); - const credentials = await WorkflowCredentials([workflow.getNode(webhook.node as string) as INode]); - - const additionalData = await WorkflowExecuteAdditionalData.getBase(credentials); + const additionalData = await WorkflowExecuteAdditionalData.getBase(); const webhookData = NodeHelpers.getNodeWebhooks(workflow, workflow.getNode(webhook.node as string) as INode, additionalData).filter((webhook) => { return (webhook.httpMethod === httpMethod && webhook.path === path); @@ -368,8 +366,7 @@ export class ActiveWorkflowRunner { const mode = 'internal'; - const credentials = await WorkflowCredentials(workflowData.nodes); - const additionalData = await WorkflowExecuteAdditionalData.getBase(credentials); + const additionalData = await WorkflowExecuteAdditionalData.getBase(); const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData); @@ -421,7 +418,6 @@ export class ActiveWorkflowRunner { // Start the workflow const runData: IWorkflowExecutionDataProcess = { - credentials: additionalData.credentials, executionMode: mode, executionData, workflowData, @@ -508,8 +504,7 @@ export class ActiveWorkflowRunner { } const mode = 'trigger'; - const credentials = await WorkflowCredentials(workflowData.nodes); - const additionalData = await WorkflowExecuteAdditionalData.getBase(credentials); + const additionalData = await WorkflowExecuteAdditionalData.getBase(); const getTriggerFunctions = this.getExecuteTriggerFunctions(workflowData, additionalData, mode, activation); const getPollFunctions = this.getExecutePollFunctions(workflowData, additionalData, mode, activation); diff --git a/packages/cli/src/CredentialsHelper.ts b/packages/cli/src/CredentialsHelper.ts index 07e9f484f7..f3427831df 100644 --- a/packages/cli/src/CredentialsHelper.ts +++ b/packages/cli/src/CredentialsHelper.ts @@ -48,16 +48,21 @@ export class CredentialsHelper extends ICredentialsHelper { * @returns {Credentials} * @memberof CredentialsHelper */ - getCredentials(name: string, type: string): Credentials { - if (!this.workflowCredentials[type]) { + async getCredentials(name: string, type: string): Promise { + + const credentialsDb = await Db.collections.Credentials?.find({type}); + + if (credentialsDb === undefined || credentialsDb.length === 0) { throw new Error(`No credentials of type "${type}" exist.`); } - if (!this.workflowCredentials[type][name]) { + + const credential = credentialsDb.find(credential => credential.name === name); + + if (credential === undefined) { throw new Error(`No credentials with name "${name}" exist for type "${type}".`); } - const credentialData = this.workflowCredentials[type][name]; - - return new Credentials(credentialData.name, credentialData.type, credentialData.nodesAccess, credentialData.data); + + return new Credentials(credential.name, credential.type, credential.nodesAccess, credential.data); } @@ -102,8 +107,8 @@ export class CredentialsHelper extends ICredentialsHelper { * @returns {ICredentialDataDecryptedObject} * @memberof CredentialsHelper */ - getDecrypted(name: string, type: string, mode: WorkflowExecuteMode, raw?: boolean, expressionResolveValues?: ICredentialsExpressionResolveValues): ICredentialDataDecryptedObject { - const credentials = this.getCredentials(name, type); + async getDecrypted(name: string, type: string, mode: WorkflowExecuteMode, raw?: boolean, expressionResolveValues?: ICredentialsExpressionResolveValues): Promise { + const credentials = await this.getCredentials(name, type); const decryptedDataOriginal = credentials.getData(this.encryptionKey); diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index d2aff0eb86..e55f77e8e6 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -457,7 +457,6 @@ export interface IProcessMessageDataHook { } export interface IWorkflowExecutionDataProcess { - credentials: IWorkflowCredentials; destinationNode?: string; executionMode: WorkflowExecuteMode; executionData?: IRunExecutionData; diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index d4341ed711..36ac50bbaa 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -66,7 +66,6 @@ import { TestWebhooks, WebhookHelpers, WebhookServer, - WorkflowCredentials, WorkflowExecuteAdditionalData, WorkflowHelpers, WorkflowRunner, @@ -764,8 +763,7 @@ class App { // If webhooks nodes exist and are active we have to wait for till we receive a call if (runData === undefined || startNodes === undefined || startNodes.length === 0 || destinationNode === undefined) { - const credentials = await WorkflowCredentials(workflowData.nodes); - const additionalData = await WorkflowExecuteAdditionalData.getBase(credentials); + const additionalData = await WorkflowExecuteAdditionalData.getBase(); const nodeTypes = NodeTypes(); const workflowInstance = new Workflow({ id: workflowData.id, name: workflowData.name, nodes: workflowData.nodes, connections: workflowData.connections, active: false, nodeTypes, staticData: undefined, settings: workflowData.settings }); const needsWebhook = await this.testWebhooks.needsWebhookData(workflowData, workflowInstance, additionalData, executionMode, activationMode, sessionId, destinationNode); @@ -779,11 +777,8 @@ class App { // For manual testing always set to not active workflowData.active = false; - const credentials = await WorkflowCredentials(workflowData.nodes); - // Start the workflow const data: IWorkflowExecutionDataProcess = { - credentials, destinationNode, executionMode, runData, @@ -880,9 +875,7 @@ class App { // @ts-ignore const loadDataInstance = new LoadNodeParameterOptions(nodeType, nodeTypes, path, JSON.parse('' + req.query.currentNodeParameters), credentials!); - const workflowData = loadDataInstance.getWorkflowData() as IWorkflowBase; - const workflowCredentials = await WorkflowCredentials(workflowData.nodes); - const additionalData = await WorkflowExecuteAdditionalData.getBase(workflowCredentials, currentNodeParameters); + const additionalData = await WorkflowExecuteAdditionalData.getBase(currentNodeParameters); return loadDataInstance.getOptions(methodName, additionalData); })); @@ -1259,15 +1252,9 @@ class App { return ''; } - // Decrypt the currently saved credentials - const workflowCredentials: IWorkflowCredentials = { - [result.type as string]: { - [result.name as string]: result as ICredentialsEncrypted, - }, - }; const mode: WorkflowExecuteMode = 'internal'; - const credentialsHelper = new CredentialsHelper(workflowCredentials, encryptionKey); - const decryptedDataOriginal = credentialsHelper.getDecrypted(result.name, result.type, mode, true); + const credentialsHelper = new CredentialsHelper(encryptionKey); + const decryptedDataOriginal = await credentialsHelper.getDecrypted(result.name, result.type, mode, true); const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, result.type, mode); const signatureMethod = _.get(oauthCredentials, 'signatureMethod') as string; @@ -1351,6 +1338,7 @@ class App { return ResponseHelper.sendErrorResponse(res, errorResponse); } + // Decrypt the currently saved credentials const workflowCredentials: IWorkflowCredentials = { [result.type as string]: { @@ -1358,10 +1346,10 @@ class App { }, }; const mode: WorkflowExecuteMode = 'internal'; - const credentialsHelper = new CredentialsHelper(workflowCredentials, encryptionKey); - const decryptedDataOriginal = credentialsHelper.getDecrypted(result.name, result.type, mode, true); + const credentialsHelper = new CredentialsHelper(encryptionKey); + const decryptedDataOriginal = await credentialsHelper.getDecrypted(result.name, result.type, mode, true); const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, result.type, mode); - + const options: OptionsWithUrl = { method: 'POST', url: _.get(oauthCredentials, 'accessTokenUrl') as string, @@ -1427,15 +1415,9 @@ class App { return ''; } - // Decrypt the currently saved credentials - const workflowCredentials: IWorkflowCredentials = { - [result.type as string]: { - [result.name as string]: result as ICredentialsEncrypted, - }, - }; const mode: WorkflowExecuteMode = 'internal'; - const credentialsHelper = new CredentialsHelper(workflowCredentials, encryptionKey); - const decryptedDataOriginal = credentialsHelper.getDecrypted(result.name, result.type, mode, true); + const credentialsHelper = new CredentialsHelper(encryptionKey); + const decryptedDataOriginal = await credentialsHelper.getDecrypted(result.name, result.type, mode, true); const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, result.type, mode); const token = new csrf(); @@ -1534,11 +1516,12 @@ class App { [result.name as string]: result as ICredentialsEncrypted, }, }; + const mode: WorkflowExecuteMode = 'internal'; - const credentialsHelper = new CredentialsHelper(workflowCredentials, encryptionKey); - const decryptedDataOriginal = credentialsHelper.getDecrypted(result.name, result.type, mode, true); + const credentialsHelper = new CredentialsHelper(encryptionKey); + const decryptedDataOriginal = await credentialsHelper.getDecrypted(result.name, result.type, mode, true); const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, result.type, mode); - + const token = new csrf(); if (decryptedDataOriginal.csrfSecret === undefined || !token.verify(decryptedDataOriginal.csrfSecret as string, state.token)) { const errorResponse = new ResponseHelper.ResponseError('The OAuth2 callback state is invalid!', undefined, 404); @@ -1735,13 +1718,10 @@ class App { const executionMode = 'retry'; - const credentials = await WorkflowCredentials(fullExecutionData.workflowData.nodes); - fullExecutionData.workflowData.active = false; // Start the workflow const data: IWorkflowExecutionDataProcess = { - credentials, executionMode, executionData: fullExecutionData.data, retryOf: req.params.id, diff --git a/packages/cli/src/WebhookHelpers.ts b/packages/cli/src/WebhookHelpers.ts index 4f6c540bf8..a88572d3ac 100644 --- a/packages/cli/src/WebhookHelpers.ts +++ b/packages/cli/src/WebhookHelpers.ts @@ -129,8 +129,7 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { } // Prepare everything that is needed to run the workflow - const credentials = await WorkflowCredentials(workflowData.nodes); - const additionalData = await WorkflowExecuteAdditionalData.getBase(credentials); + const additionalData = await WorkflowExecuteAdditionalData.getBase(); // Add the Response and Request so that this data can be accessed in the node additionalData.httpRequest = req; @@ -276,7 +275,6 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { } const runData: IWorkflowExecutionDataProcess = { - credentials, executionMode, executionData: runExecutionData, sessionId, diff --git a/packages/cli/src/WorkflowExecuteAdditionalData.ts b/packages/cli/src/WorkflowExecuteAdditionalData.ts index 5c5ddfe8af..8a55fcdb08 100644 --- a/packages/cli/src/WorkflowExecuteAdditionalData.ts +++ b/packages/cli/src/WorkflowExecuteAdditionalData.ts @@ -545,12 +545,7 @@ export async function getRunData(workflowData: IWorkflowBase, inputData?: INodeE }, }; - // Get the needed credentials for the current workflow as they will differ to the ones of the - // calling workflow. - const credentials = await WorkflowCredentials(workflowData!.nodes); - const runData: IWorkflowExecutionDataProcess = { - credentials, executionMode: mode, executionData: runExecutionData, // @ts-ignore @@ -618,13 +613,9 @@ export async function executeWorkflow(workflowInfo: IExecuteWorkflowInfo, additi let data; try { - // Get the needed credentials for the current workflow as they will differ to the ones of the - // calling workflow. - const credentials = await WorkflowCredentials(workflowData!.nodes); - // Create new additionalData to have different workflow loaded and to call // different webooks - const additionalDataIntegrated = await getBase(credentials); + const additionalDataIntegrated = await getBase(); additionalDataIntegrated.hooks = getWorkflowHooksIntegrated(runData.executionMode, executionId, workflowData!, { parentProcessMode: additionalData.hooks!.mode }); // Make sure we pass on the original executeWorkflow function we received // This one already contains changes to talk to parent process @@ -735,7 +726,7 @@ export function sendMessageToUI(source: string, message: any) { // tslint:disabl * @param {INodeParameters} currentNodeParameters * @returns {Promise} */ -export async function getBase(credentials: IWorkflowCredentials, currentNodeParameters?: INodeParameters, executionTimeoutTimestamp?: number): Promise { +export async function getBase(currentNodeParameters?: INodeParameters, executionTimeoutTimestamp?: number): Promise { const urlBaseWebhook = WebhookHelpers.getWebhookBaseUrl(); const timezone = config.get('generic.timezone') as string; @@ -748,8 +739,7 @@ export async function getBase(credentials: IWorkflowCredentials, currentNodePara } return { - credentials, - credentialsHelper: new CredentialsHelper(credentials, encryptionKey), + credentialsHelper: new CredentialsHelper(encryptionKey), encryptionKey, executeWorkflow, restApiUrl: urlBaseWebhook + config.get('endpoints.rest') as string, diff --git a/packages/cli/src/WorkflowHelpers.ts b/packages/cli/src/WorkflowHelpers.ts index 68718dc4cf..87e5fe3366 100644 --- a/packages/cli/src/WorkflowHelpers.ts +++ b/packages/cli/src/WorkflowHelpers.ts @@ -144,10 +144,7 @@ export async function executeErrorWorkflow(workflowId: string, workflowErrorData }, }; - const credentials = await WorkflowCredentials(workflowData.nodes); - const runData: IWorkflowExecutionDataProcess = { - credentials, executionMode, executionData: runExecutionData, workflowData, diff --git a/packages/cli/src/WorkflowRunner.ts b/packages/cli/src/WorkflowRunner.ts index 07f9b91fe2..564d01a975 100644 --- a/packages/cli/src/WorkflowRunner.ts +++ b/packages/cli/src/WorkflowRunner.ts @@ -183,7 +183,7 @@ export class WorkflowRunner { } const workflow = new Workflow({ id: data.workflowData.id as string | undefined, name: data.workflowData.name, nodes: data.workflowData!.nodes, connections: data.workflowData!.connections, active: data.workflowData!.active, nodeTypes, staticData: data.workflowData!.staticData }); - const additionalData = await WorkflowExecuteAdditionalData.getBase(data.credentials, undefined, workflowTimeout <= 0 ? undefined : Date.now() + workflowTimeout * 1000); + const additionalData = await WorkflowExecuteAdditionalData.getBase(undefined, workflowTimeout <= 0 ? undefined : Date.now() + workflowTimeout * 1000); // Register the active execution const executionId = await this.activeExecutions.add(data, undefined); @@ -423,43 +423,14 @@ export class WorkflowRunner { // Register the active execution const executionId = await this.activeExecutions.add(data, subprocess); - // Check if workflow contains a "executeWorkflow" Node as in this - // case we can not know which nodeTypes and credentialTypes will - // be needed and so have to load all of them in the workflowRunnerProcess - let loadAllNodeTypes = false; - for (const node of data.workflowData.nodes) { - if (node.type === 'n8n-nodes-base.executeWorkflow') { - loadAllNodeTypes = true; - break; - } - } - - let nodeTypeData: ITransferNodeTypes; - let credentialTypeData: ICredentialsTypeData; - let credentialsOverwrites = this.credentialsOverwrites; - - if (loadAllNodeTypes === true) { - // Supply all nodeTypes and credentialTypes - nodeTypeData = WorkflowHelpers.getAllNodeTypeData(); - const credentialTypes = CredentialTypes(); - credentialTypeData = credentialTypes.credentialTypes; - } else { - // Supply only nodeTypes, credentialTypes and overwrites that the workflow needs - nodeTypeData = WorkflowHelpers.getNodeTypeData(data.workflowData.nodes); - credentialTypeData = WorkflowHelpers.getCredentialsData(data.credentials); - - credentialsOverwrites = {}; - for (const credentialName of Object.keys(credentialTypeData)) { - if (this.credentialsOverwrites[credentialName] !== undefined) { - credentialsOverwrites[credentialName] = this.credentialsOverwrites[credentialName]; - } - } - } + // Supply all nodeTypes and credentialTypes + const nodeTypeData = WorkflowHelpers.getAllNodeTypeData() as ITransferNodeTypes; + const credentialTypes = CredentialTypes(); (data as unknown as IWorkflowExecutionDataProcessWithExecution).executionId = executionId; (data as unknown as IWorkflowExecutionDataProcessWithExecution).nodeTypeData = nodeTypeData; - (data as unknown as IWorkflowExecutionDataProcessWithExecution).credentialsOverwrite = credentialsOverwrites; - (data as unknown as IWorkflowExecutionDataProcessWithExecution).credentialsTypeData = credentialTypeData; // TODO: Still needs correct value + (data as unknown as IWorkflowExecutionDataProcessWithExecution).credentialsOverwrite = this.credentialsOverwrites; + (data as unknown as IWorkflowExecutionDataProcessWithExecution).credentialsTypeData = credentialTypes.credentialTypes; const workflowHooks = WorkflowExecuteAdditionalData.getWorkflowHooksMain(data, executionId); diff --git a/packages/cli/src/WorkflowRunnerProcess.ts b/packages/cli/src/WorkflowRunnerProcess.ts index 321389ae2f..715b8ada44 100644 --- a/packages/cli/src/WorkflowRunnerProcess.ts +++ b/packages/cli/src/WorkflowRunnerProcess.ts @@ -111,9 +111,22 @@ export class WorkflowRunnerProcess { const externalHooks = ExternalHooks(); await externalHooks.init(); - // This code has been split into 3 ifs just to make it easier to understand + // Credentials should now be loaded from database. + // We check if any node uses credentials. If it does, then + // init database. + let shouldInitializaDb = false; + inputData.workflowData.nodes.map(node => { + if (Object.keys(node.credentials === undefined ? {} : node.credentials).length > 0) { + shouldInitializaDb = true; + } + }); + + // This code has been split into 4 ifs just to make it easier to understand // Can be made smaller but in the end it will make it impossible to read. - if (inputData.workflowData.settings !== undefined && inputData.workflowData.settings.saveExecutionProgress === true) { + if (shouldInitializaDb) { + // initialize db as we need to load credentials + await Db.init(); + } else if (inputData.workflowData.settings !== undefined && inputData.workflowData.settings.saveExecutionProgress === true) { // Workflow settings specifying it should save await Db.init(); } else if (inputData.workflowData.settings !== undefined && inputData.workflowData.settings.saveExecutionProgress !== false && config.get('executions.saveExecutionProgress') as boolean) { @@ -135,7 +148,7 @@ export class WorkflowRunnerProcess { } this.workflow = new Workflow({ id: this.data.workflowData.id as string | undefined, name: this.data.workflowData.name, nodes: this.data.workflowData!.nodes, connections: this.data.workflowData!.connections, active: this.data.workflowData!.active, nodeTypes, staticData: this.data.workflowData!.staticData, settings: this.data.workflowData!.settings }); - const additionalData = await WorkflowExecuteAdditionalData.getBase(this.data.credentials, undefined, workflowTimeout <= 0 ? undefined : Date.now() + workflowTimeout * 1000); + const additionalData = await WorkflowExecuteAdditionalData.getBase(undefined, workflowTimeout <= 0 ? undefined : Date.now() + workflowTimeout * 1000); additionalData.hooks = this.getProcessForwardHooks(); additionalData.sendMessageToUI = async (source: string, message: any) => { // tslint:disable-line:no-any diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 1042257e65..cb94d6c2d2 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -155,8 +155,8 @@ export async function prepareBinaryData(binaryData: Buffer, filePath?: string, m * * @returns */ -export function requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, node: INode, additionalData: IWorkflowExecuteAdditionalData, oAuth2Options?: IOAuth2Options) { - const credentials = this.getCredentials(credentialsType) as ICredentialDataDecryptedObject; +export async function requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, node: INode, additionalData: IWorkflowExecuteAdditionalData, oAuth2Options?: IOAuth2Options) { + const credentials = await this.getCredentials(credentialsType) as ICredentialDataDecryptedObject; if (credentials === undefined) { throw new Error('No credentials got returned!'); @@ -244,8 +244,8 @@ export function requestOAuth2(this: IAllExecuteFunctions, credentialsType: strin * @param {(OptionsWithUrl | requestPromise.RequestPromiseOptions)} requestOptionså * @returns */ -export function requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | OptionsWithUri | requestPromise.RequestPromiseOptions) { - const credentials = this.getCredentials(credentialsType) as ICredentialDataDecryptedObject; +export async function requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | OptionsWithUri | requestPromise.RequestPromiseOptions) { + const credentials = await this.getCredentials(credentialsType) as ICredentialDataDecryptedObject; if (credentials === undefined) { throw new Error('No credentials got returned!'); @@ -332,7 +332,7 @@ export function returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExe * @param {IWorkflowExecuteAdditionalData} additionalData * @returns {(ICredentialDataDecryptedObject | undefined)} */ -export function getCredentials(workflow: Workflow, node: INode, type: string, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, runExecutionData?: IRunExecutionData | null, runIndex?: number, connectionInputData?: INodeExecutionData[], itemIndex?: number): ICredentialDataDecryptedObject | undefined { +export async function getCredentials(workflow: Workflow, node: INode, type: string, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, runExecutionData?: IRunExecutionData | null, runIndex?: number, connectionInputData?: INodeExecutionData[], itemIndex?: number): Promise { // Get the NodeType as it has the information if the credentials are required const nodeType = workflow.nodeTypes.getByName(node.type); @@ -386,7 +386,7 @@ export function getCredentials(workflow: Workflow, node: INode, type: string, ad const name = node.credentials[type]; - const decryptedDataObject = additionalData.credentialsHelper.getDecrypted(name, type, mode, false, expressionResolveValues); + const decryptedDataObject = await additionalData.credentialsHelper.getDecrypted(name, type, mode, false, expressionResolveValues); return decryptedDataObject; } @@ -570,8 +570,8 @@ export function getExecutePollFunctions(workflow: Workflow, node: INode, additio __emit: (data: INodeExecutionData[][]): void => { throw new Error('Overwrite NodeExecuteFunctions.getExecutePullFunctions.__emit function!'); }, - getCredentials(type: string): ICredentialDataDecryptedObject | undefined { - return getCredentials(workflow, node, type, additionalData, mode); + async getCredentials(type: string): Promise { + return await getCredentials(workflow, node, type, additionalData, mode); }, getMode: (): WorkflowExecuteMode => { return mode; @@ -636,8 +636,8 @@ export function getExecuteTriggerFunctions(workflow: Workflow, node: INode, addi emit: (data: INodeExecutionData[][]): void => { throw new Error('Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!'); }, - getCredentials(type: string): ICredentialDataDecryptedObject | undefined { - return getCredentials(workflow, node, type, additionalData, mode); + async getCredentials(type: string): Promise { + return await getCredentials(workflow, node, type, additionalData, mode); }, getNode: () => { return getNode(node); @@ -714,8 +714,8 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx getContext(type: string): IContextObject { return NodeHelpers.getContext(runExecutionData, type, node); }, - getCredentials(type: string, itemIndex?: number): ICredentialDataDecryptedObject | undefined { - return getCredentials(workflow, node, type, additionalData, mode, runExecutionData, runIndex, connectionInputData, itemIndex); + async getCredentials(type: string, itemIndex?: number): Promise { + return await getCredentials(workflow, node, type, additionalData, mode, runExecutionData, runIndex, connectionInputData, itemIndex); }, getInputData: (inputIndex = 0, inputName = 'main') => { @@ -824,8 +824,8 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData: getContext(type: string): IContextObject { return NodeHelpers.getContext(runExecutionData, type, node); }, - getCredentials(type: string): ICredentialDataDecryptedObject | undefined { - return getCredentials(workflow, node, type, additionalData, mode, runExecutionData, runIndex, connectionInputData, itemIndex); + async getCredentials(type: string): Promise { + return await getCredentials(workflow, node, type, additionalData, mode, runExecutionData, runIndex, connectionInputData, itemIndex); }, getInputData: (inputIndex = 0, inputName = 'main') => { if (!inputData.hasOwnProperty(inputName)) { @@ -904,8 +904,8 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData: export function getLoadOptionsFunctions(workflow: Workflow, node: INode, path: string, additionalData: IWorkflowExecuteAdditionalData): ILoadOptionsFunctions { return ((workflow: Workflow, node: INode, path: string) => { const that = { - getCredentials(type: string): ICredentialDataDecryptedObject | undefined { - return getCredentials(workflow, node, type, additionalData, 'internal'); + async getCredentials(type: string): Promise { + return await getCredentials(workflow, node, type, additionalData, 'internal'); }, getCurrentNodeParameter: (parameterPath: string): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object | undefined => { const nodeParameters = additionalData.currentNodeParameters; @@ -965,8 +965,8 @@ export function getLoadOptionsFunctions(workflow: Workflow, node: INode, path: s export function getExecuteHookFunctions(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, activation: WorkflowActivateMode, isTest?: boolean, webhookData?: IWebhookData): IHookFunctions { return ((workflow: Workflow, node: INode) => { const that = { - getCredentials(type: string): ICredentialDataDecryptedObject | undefined { - return getCredentials(workflow, node, type, additionalData, mode); + async getCredentials(type: string): Promise { + return await getCredentials(workflow, node, type, additionalData, mode); }, getMode: (): WorkflowExecuteMode => { return mode; @@ -1042,8 +1042,8 @@ export function getExecuteWebhookFunctions(workflow: Workflow, node: INode, addi } return additionalData.httpRequest.body; }, - getCredentials(type: string): ICredentialDataDecryptedObject | undefined { - return getCredentials(workflow, node, type, additionalData, mode); + async getCredentials(type: string): Promise { + return await getCredentials(workflow, node, type, additionalData, mode); }, getHeaderData(): object { if (additionalData.httpRequest === undefined) { diff --git a/packages/core/test/Helpers.ts b/packages/core/test/Helpers.ts index bba3a3452d..b5662a24e7 100644 --- a/packages/core/test/Helpers.ts +++ b/packages/core/test/Helpers.ts @@ -26,12 +26,14 @@ import { export class CredentialsHelper extends ICredentialsHelper { - getDecrypted(name: string, type: string): ICredentialDataDecryptedObject { - return {}; + getDecrypted(name: string, type: string): Promise { + return new Promise(res => res({})); } - getCredentials(name: string, type: string): Credentials { - return new Credentials('', '', [], ''); + getCredentials(name: string, type: string): Promise { + return new Promise(res => { + res(new Credentials('', '', [], '')); + }); } async updateCredentials(name: string, type: string, data: ICredentialDataDecryptedObject): Promise {} @@ -748,8 +750,7 @@ export function WorkflowExecuteAdditionalData(waitPromise: IDeferredPromise => {}, // tslint:disable-line:no-any sendMessageToUI: (message: string) => {}, diff --git a/packages/nodes-base/nodes/ActionNetwork/GenericFunctions.ts b/packages/nodes-base/nodes/ActionNetwork/GenericFunctions.ts index 32bb775feb..da67bd3b76 100644 --- a/packages/nodes-base/nodes/ActionNetwork/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ActionNetwork/GenericFunctions.ts @@ -35,7 +35,7 @@ export async function actionNetworkApiRequest( body: IDataObject = {}, qs: IDataObject = {}, ) { - const credentials = this.getCredentials('actionNetworkApi') as { apiKey: string } | undefined; + const credentials = await this.getCredentials('actionNetworkApi') as { apiKey: string } | undefined; if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts b/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts index 172cbd37ec..0fc30fed51 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts @@ -26,7 +26,7 @@ export interface IProduct { * @returns {Promise} */ export async function activeCampaignApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject, dataKey?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('activeCampaignApi'); + const credentials = await this.getCredentials('activeCampaignApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/AcuityScheduling/GenericFunctions.ts b/packages/nodes-base/nodes/AcuityScheduling/GenericFunctions.ts index e974fc8042..687871a814 100644 --- a/packages/nodes-base/nodes/AcuityScheduling/GenericFunctions.ts +++ b/packages/nodes-base/nodes/AcuityScheduling/GenericFunctions.ts @@ -25,7 +25,7 @@ export async function acuitySchedulingApiRequest(this: IHookFunctions | IExecute try { if (authenticationMethod === 'apiKey') { - const credentials = this.getCredentials('acuitySchedulingApi'); + const credentials = await this.getCredentials('acuitySchedulingApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Affinity/GenericFunctions.ts b/packages/nodes-base/nodes/Affinity/GenericFunctions.ts index 04443d4d79..f16c861b1d 100644 --- a/packages/nodes-base/nodes/Affinity/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Affinity/GenericFunctions.ts @@ -18,7 +18,7 @@ import { export async function affinityApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('affinityApi'); + const credentials = await this.getCredentials('affinityApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts b/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts index d0ee821a01..0143b0f624 100644 --- a/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts +++ b/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts @@ -17,7 +17,7 @@ import { IContactUpdate } from './ContactInterface'; export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('agileCrmApi'); + const credentials = await this.getCredentials('agileCrmApi'); const options: OptionsWithUri = { method, headers: { @@ -46,7 +46,7 @@ export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunction export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method = 'PUT', endpoint?: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('agileCrmApi'); + const credentials = await this.getCredentials('agileCrmApi'); const baseUri = `https://${credentials!.subdomain}.agilecrm.com/dev/`; const options: OptionsWithUri = { method, diff --git a/packages/nodes-base/nodes/Airtable/GenericFunctions.ts b/packages/nodes-base/nodes/Airtable/GenericFunctions.ts index 54eb8ea387..e85d1867f3 100644 --- a/packages/nodes-base/nodes/Airtable/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Airtable/GenericFunctions.ts @@ -40,7 +40,7 @@ export interface IRecord { * @returns {Promise} */ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: object, query?: IDataObject, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('airtableApi'); + const credentials = await this.getCredentials('airtableApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Amqp/Amqp.node.ts b/packages/nodes-base/nodes/Amqp/Amqp.node.ts index f23a085a4d..a50508930b 100644 --- a/packages/nodes-base/nodes/Amqp/Amqp.node.ts +++ b/packages/nodes-base/nodes/Amqp/Amqp.node.ts @@ -98,7 +98,7 @@ export class Amqp implements INodeType { async execute(this: IExecuteFunctions): Promise { try { - const credentials = this.getCredentials('amqp'); + const credentials = await this.getCredentials('amqp'); if (!credentials) { throw new NodeOperationError(this.getNode(), 'Credentials are mandatory!'); } diff --git a/packages/nodes-base/nodes/Amqp/AmqpTrigger.node.ts b/packages/nodes-base/nodes/Amqp/AmqpTrigger.node.ts index f7f3291923..c7f7b51e65 100644 --- a/packages/nodes-base/nodes/Amqp/AmqpTrigger.node.ts +++ b/packages/nodes-base/nodes/Amqp/AmqpTrigger.node.ts @@ -132,7 +132,7 @@ export class AmqpTrigger implements INodeType { async trigger(this: ITriggerFunctions): Promise { - const credentials = this.getCredentials('amqp'); + const credentials = await this.getCredentials('amqp'); if (!credentials) { throw new NodeOperationError(this.getNode(), 'Credentials are mandatory!'); } diff --git a/packages/nodes-base/nodes/ApiTemplateIo/GenericFunctions.ts b/packages/nodes-base/nodes/ApiTemplateIo/GenericFunctions.ts index e096d81acf..c330d5ae15 100644 --- a/packages/nodes-base/nodes/ApiTemplateIo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ApiTemplateIo/GenericFunctions.ts @@ -15,7 +15,7 @@ export async function apiTemplateIoApiRequest( qs = {}, body = {}, ) { - const { apiKey } = this.getCredentials('apiTemplateIoApi') as { apiKey: string }; + const { apiKey } = await this.getCredentials('apiTemplateIoApi') as { apiKey: string }; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Asana/GenericFunctions.ts b/packages/nodes-base/nodes/Asana/GenericFunctions.ts index 6741ef96fb..de62487dc6 100644 --- a/packages/nodes-base/nodes/Asana/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Asana/GenericFunctions.ts @@ -42,7 +42,7 @@ export async function asanaApiRequest(this: IHookFunctions | IExecuteFunctions | try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('asanaApi'); + const credentials = await this.getCredentials('asanaApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Automizy/GenericFunctions.ts b/packages/nodes-base/nodes/Automizy/GenericFunctions.ts index 8db073461e..2644bbf225 100644 --- a/packages/nodes-base/nodes/Automizy/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Automizy/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function automizyApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('automizyApi') as IDataObject; + const credentials = await this.getCredentials('automizyApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Autopilot/GenericFunctions.ts b/packages/nodes-base/nodes/Autopilot/GenericFunctions.ts index 4431e433d1..c70a139c12 100644 --- a/packages/nodes-base/nodes/Autopilot/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Autopilot/GenericFunctions.ts @@ -16,7 +16,7 @@ import { export async function autopilotApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('autopilotApi') as IDataObject; + const credentials = await this.getCredentials('autopilotApi') as IDataObject; const apiKey = `${credentials.apiKey}`; diff --git a/packages/nodes-base/nodes/Aws/Comprehend/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Comprehend/GenericFunctions.ts index 13c389e26a..48703ee25b 100644 --- a/packages/nodes-base/nodes/Aws/Comprehend/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Comprehend/GenericFunctions.ts @@ -38,7 +38,7 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr } export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('aws'); + const credentials = await this.getCredentials('aws'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts index e9a5a0316b..faa08410da 100644 --- a/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts @@ -36,7 +36,7 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr } export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: object | IRequestBody, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('aws'); + const credentials = await this.getCredentials('aws'); if (credentials === undefined) { throw new Error('No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Aws/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/GenericFunctions.ts index 59caff7b82..afea4f9e13 100644 --- a/packages/nodes-base/nodes/Aws/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/GenericFunctions.ts @@ -29,7 +29,7 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr } export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('aws'); + const credentials = await this.getCredentials('aws'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Aws/Rekognition/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Rekognition/GenericFunctions.ts index 38a41a3235..b19dd1e576 100644 --- a/packages/nodes-base/nodes/Aws/Rekognition/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Rekognition/GenericFunctions.ts @@ -36,7 +36,7 @@ import { } from 'change-case'; export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string | Buffer | IDataObject, query: IDataObject = {}, headers?: object, option: IDataObject = {}, region?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('aws'); + const credentials = await this.getCredentials('aws'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts b/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts index a58e122f12..8f12c0f306 100644 --- a/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts +++ b/packages/nodes-base/nodes/Aws/S3/AwsS3.node.ts @@ -114,7 +114,7 @@ export class AwsS3 implements INodeType { if (resource === 'bucket') { //https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html if (operation === 'create') { - const credentials = this.getCredentials('aws'); + const credentials = await this.getCredentials('aws'); const name = this.getNodeParameter('name', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; if (additionalFields.acl) { diff --git a/packages/nodes-base/nodes/Aws/S3/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/S3/GenericFunctions.ts index b3dc8bd46a..7d183dadde 100644 --- a/packages/nodes-base/nodes/Aws/S3/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/S3/GenericFunctions.ts @@ -30,7 +30,7 @@ import { } from 'n8n-workflow'; export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string | Buffer, query: IDataObject = {}, headers?: object, option: IDataObject = {}, region?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('aws'); + const credentials = await this.getCredentials('aws'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Aws/SES/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/SES/GenericFunctions.ts index 46b33d6a09..20701651d3 100644 --- a/packages/nodes-base/nodes/Aws/SES/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/SES/GenericFunctions.ts @@ -30,7 +30,7 @@ import { } from 'lodash'; export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('aws'); + const credentials = await this.getCredentials('aws'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Aws/Transcribe/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/Transcribe/GenericFunctions.ts index 177b349906..f94823c376 100644 --- a/packages/nodes-base/nodes/Aws/Transcribe/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/Transcribe/GenericFunctions.ts @@ -41,7 +41,7 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr } export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('aws'); + const credentials = await this.getCredentials('aws'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Bannerbear/GenericFunctions.ts b/packages/nodes-base/nodes/Bannerbear/GenericFunctions.ts index 45d7996ead..32a750a2d0 100644 --- a/packages/nodes-base/nodes/Bannerbear/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bannerbear/GenericFunctions.ts @@ -21,7 +21,7 @@ import { export async function bannerbearApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('bannerbearApi'); + const credentials = await this.getCredentials('bannerbearApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Baserow/Baserow.node.ts b/packages/nodes-base/nodes/Baserow/Baserow.node.ts index 951d0c27a6..a534a6b28d 100644 --- a/packages/nodes-base/nodes/Baserow/Baserow.node.ts +++ b/packages/nodes-base/nodes/Baserow/Baserow.node.ts @@ -114,7 +114,7 @@ export class Baserow implements INodeType { methods = { loadOptions: { async getDatabaseIds(this: ILoadOptionsFunctions) { - const credentials = this.getCredentials('baserowApi') as BaserowCredentials; + const credentials = await this.getCredentials('baserowApi') as BaserowCredentials; const jwtToken = await getJwtToken.call(this, credentials); const endpoint = '/api/applications/'; const databases = await baserowApiRequest.call(this, 'GET', endpoint, {}, {}, jwtToken) as LoadedResource[]; @@ -122,7 +122,7 @@ export class Baserow implements INodeType { }, async getTableIds(this: ILoadOptionsFunctions) { - const credentials = this.getCredentials('baserowApi') as BaserowCredentials; + const credentials = await this.getCredentials('baserowApi') as BaserowCredentials; const jwtToken = await getJwtToken.call(this, credentials); const databaseId = this.getNodeParameter('databaseId', 0) as string; const endpoint = `/api/database/tables/database/${databaseId}`; @@ -131,7 +131,7 @@ export class Baserow implements INodeType { }, async getTableFields(this: ILoadOptionsFunctions) { - const credentials = this.getCredentials('baserowApi') as BaserowCredentials; + const credentials = await this.getCredentials('baserowApi') as BaserowCredentials; const jwtToken = await getJwtToken.call(this, credentials); const tableId = this.getNodeParameter('tableId', 0) as string; const endpoint = `/api/database/fields/table/${tableId}/`; @@ -148,7 +148,7 @@ export class Baserow implements INodeType { const operation = this.getNodeParameter('operation', 0) as Operation; const tableId = this.getNodeParameter('tableId', 0) as string; - const credentials = this.getCredentials('baserowApi') as BaserowCredentials; + const credentials = await this.getCredentials('baserowApi') as BaserowCredentials; const jwtToken = await getJwtToken.call(this, credentials); const fields = await mapper.getTableFields.call(this, tableId, jwtToken); mapper.createMappings(fields); diff --git a/packages/nodes-base/nodes/Baserow/GenericFunctions.ts b/packages/nodes-base/nodes/Baserow/GenericFunctions.ts index e360b6192b..e081825177 100644 --- a/packages/nodes-base/nodes/Baserow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Baserow/GenericFunctions.ts @@ -30,7 +30,7 @@ export async function baserowApiRequest( qs: IDataObject = {}, jwtToken: string, ) { - const credentials = this.getCredentials('baserowApi') as BaserowCredentials; + const credentials = await this.getCredentials('baserowApi') as BaserowCredentials; if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Beeminder/Beeminder.node.functions.ts b/packages/nodes-base/nodes/Beeminder/Beeminder.node.functions.ts index 17cf295342..eee387d7e0 100644 --- a/packages/nodes-base/nodes/Beeminder/Beeminder.node.functions.ts +++ b/packages/nodes-base/nodes/Beeminder/Beeminder.node.functions.ts @@ -16,7 +16,7 @@ import { } from './GenericFunctions'; export async function createDatapoint(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, data: IDataObject) { - const credentials = this.getCredentials('beeminderApi'); + const credentials = await this.getCredentials('beeminderApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -28,7 +28,7 @@ export async function createDatapoint(this: IExecuteFunctions | IWebhookFunction } export async function getAllDatapoints(this: IExecuteFunctions | IHookFunctions | ILoadOptionsFunctions, data: IDataObject) { - const credentials = this.getCredentials('beeminderApi'); + const credentials = await this.getCredentials('beeminderApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -44,7 +44,7 @@ export async function getAllDatapoints(this: IExecuteFunctions | IHookFunctions } export async function updateDatapoint(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, data: IDataObject) { - const credentials = this.getCredentials('beeminderApi'); + const credentials = await this.getCredentials('beeminderApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -56,7 +56,7 @@ export async function updateDatapoint(this: IExecuteFunctions | IWebhookFunction } export async function deleteDatapoint(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, data: IDataObject) { - const credentials = this.getCredentials('beeminderApi'); + const credentials = await this.getCredentials('beeminderApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Beeminder/Beeminder.node.ts b/packages/nodes-base/nodes/Beeminder/Beeminder.node.ts index 490d134af7..66f2457384 100644 --- a/packages/nodes-base/nodes/Beeminder/Beeminder.node.ts +++ b/packages/nodes-base/nodes/Beeminder/Beeminder.node.ts @@ -306,7 +306,7 @@ export class Beeminder implements INodeType { // select them easily async getGoals(this: ILoadOptionsFunctions): Promise { - const credentials = this.getCredentials('beeminderApi'); + const credentials = await this.getCredentials('beeminderApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Beeminder/GenericFunctions.ts b/packages/nodes-base/nodes/Beeminder/GenericFunctions.ts index 722646f40b..cc8162fbd6 100644 --- a/packages/nodes-base/nodes/Beeminder/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Beeminder/GenericFunctions.ts @@ -18,7 +18,7 @@ const BEEMINDER_URI = 'https://www.beeminder.com/api/v1'; export async function beeminderApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('beeminderApi') as IDataObject; + const credentials = await this.getCredentials('beeminderApi') as IDataObject; Object.assign(body, { auth_token: credentials.authToken }); diff --git a/packages/nodes-base/nodes/Bitbucket/BitbucketTrigger.node.ts b/packages/nodes-base/nodes/Bitbucket/BitbucketTrigger.node.ts index 8348977ef3..96da977c40 100644 --- a/packages/nodes-base/nodes/Bitbucket/BitbucketTrigger.node.ts +++ b/packages/nodes-base/nodes/Bitbucket/BitbucketTrigger.node.ts @@ -221,7 +221,7 @@ export class BitbucketTrigger implements INodeType { // Get all the repositories to display them to user so that he can // select them easily async getRepositories(this: ILoadOptionsFunctions): Promise { - const credentials = this.getCredentials('bitbucketApi'); + const credentials = await this.getCredentials('bitbucketApi'); const returnData: INodePropertyOptions[] = []; const repositories = await bitbucketApiRequestAllItems.call(this, 'values', 'GET', `/repositories/${credentials!.username}`); for (const repository of repositories) { @@ -261,7 +261,7 @@ export class BitbucketTrigger implements INodeType { default: { async checkExists(this: IHookFunctions): Promise { let endpoint = ''; - const credentials = this.getCredentials('bitbucketApi'); + const credentials = await this.getCredentials('bitbucketApi'); const resource = this.getNodeParameter('resource', 0) as string; const webhookData = this.getWorkflowStaticData('node'); if (webhookData.webhookId === undefined) { @@ -292,7 +292,7 @@ export class BitbucketTrigger implements INodeType { const webhookData = this.getWorkflowStaticData('node'); const events = this.getNodeParameter('events') as string[]; const resource = this.getNodeParameter('resource', 0) as string; - const credentials = this.getCredentials('bitbucketApi'); + const credentials = await this.getCredentials('bitbucketApi'); if (resource === 'user') { endpoint = `/users/${credentials!.username}/hooks`; @@ -318,7 +318,7 @@ export class BitbucketTrigger implements INodeType { async delete(this: IHookFunctions): Promise { let endpoint = ''; const webhookData = this.getWorkflowStaticData('node'); - const credentials = this.getCredentials('bitbucketApi'); + const credentials = await this.getCredentials('bitbucketApi'); const resource = this.getNodeParameter('resource', 0) as string; if (resource === 'user') { endpoint = `/users/${credentials!.username}/hooks/${webhookData.webhookId}`; diff --git a/packages/nodes-base/nodes/Bitbucket/GenericFunctions.ts b/packages/nodes-base/nodes/Bitbucket/GenericFunctions.ts index 3c2f88ab23..8ac1050ebe 100644 --- a/packages/nodes-base/nodes/Bitbucket/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bitbucket/GenericFunctions.ts @@ -8,7 +8,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function bitbucketApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('bitbucketApi'); + const credentials = await this.getCredentials('bitbucketApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Bitly/GenericFunctions.ts b/packages/nodes-base/nodes/Bitly/GenericFunctions.ts index 3875d10182..2edb001f1c 100644 --- a/packages/nodes-base/nodes/Bitly/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bitly/GenericFunctions.ts @@ -30,7 +30,7 @@ export async function bitlyApiRequest(this: IHookFunctions | IExecuteFunctions | try{ if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('bitlyApi'); + const credentials = await this.getCredentials('bitlyApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Bitwarden/GenericFunctions.ts b/packages/nodes-base/nodes/Bitwarden/GenericFunctions.ts index 48e739268c..e952d8df9d 100644 --- a/packages/nodes-base/nodes/Bitwarden/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bitwarden/GenericFunctions.ts @@ -25,6 +25,7 @@ export async function bitwardenApiRequest( token: string, ): Promise { // tslint:disable-line:no-any + const baseUrl = await getBaseUrl.call(this); const options: OptionsWithUri = { headers: { 'user-agent': 'n8n', @@ -34,7 +35,7 @@ export async function bitwardenApiRequest( method, qs, body, - uri: `${getBaseUrl.call(this)}${endpoint}`, + uri: `${baseUrl}${endpoint}`, json: true, }; @@ -60,7 +61,7 @@ export async function getAccessToken( this: IExecuteFunctions | ILoadOptionsFunctions, ): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('bitwardenApi') as IDataObject; + const credentials = await this.getCredentials('bitwardenApi') as IDataObject; const options: OptionsWithUri = { headers: { @@ -76,7 +77,7 @@ export async function getAccessToken( deviceType: 2, // https://github.com/bitwarden/server/blob/master/src/Core/Enums/DeviceType.cs deviceIdentifier: 'n8n', }, - uri: getTokenUrl.call(this), + uri: await getTokenUrl.call(this), json: true, }; @@ -114,8 +115,8 @@ export async function handleGetAll( /** * Return the access token URL based on the user's environment. */ -function getTokenUrl(this: IExecuteFunctions | ILoadOptionsFunctions) { - const { environment, domain } = this.getCredentials('bitwardenApi') as IDataObject; + async function getTokenUrl(this: IExecuteFunctions | ILoadOptionsFunctions) { + const { environment, domain } = await this.getCredentials('bitwardenApi') as IDataObject; return environment === 'cloudHosted' ? 'https://identity.bitwarden.com/connect/token' @@ -126,8 +127,8 @@ function getTokenUrl(this: IExecuteFunctions | ILoadOptionsFunctions) { /** * Return the base API URL based on the user's environment. */ -function getBaseUrl(this: IExecuteFunctions | ILoadOptionsFunctions) { - const { environment, domain } = this.getCredentials('bitwardenApi') as IDataObject; +async function getBaseUrl(this: IExecuteFunctions | ILoadOptionsFunctions) { + const { environment, domain } = await this.getCredentials('bitwardenApi') as IDataObject; return environment === 'cloudHosted' ? 'https://api.bitwarden.com' diff --git a/packages/nodes-base/nodes/Brandfetch/GenericFunctions.ts b/packages/nodes-base/nodes/Brandfetch/GenericFunctions.ts index 83c404e869..4400f52e3f 100644 --- a/packages/nodes-base/nodes/Brandfetch/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Brandfetch/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function brandfetchApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { - const credentials = this.getCredentials('brandfetchApi'); + const credentials = await this.getCredentials('brandfetchApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Bubble/GenericFunctions.ts b/packages/nodes-base/nodes/Bubble/GenericFunctions.ts index 981b9e10c8..de785babf5 100644 --- a/packages/nodes-base/nodes/Bubble/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Bubble/GenericFunctions.ts @@ -24,7 +24,7 @@ export async function bubbleApiRequest( qs: IDataObject, ) { - const { apiToken, appName, domain, environment, hosting } = this.getCredentials('bubbleApi') as { + const { apiToken, appName, domain, environment, hosting } = await this.getCredentials('bubbleApi') as { apiToken: string, appName: string, domain: string, diff --git a/packages/nodes-base/nodes/Calendly/GenericFunctions.ts b/packages/nodes-base/nodes/Calendly/GenericFunctions.ts index d2b1e6acf5..1557e1cd84 100644 --- a/packages/nodes-base/nodes/Calendly/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Calendly/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function calendlyApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('calendlyApi'); + const credentials = await this.getCredentials('calendlyApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Chargebee/Chargebee.node.ts b/packages/nodes-base/nodes/Chargebee/Chargebee.node.ts index 36aa052cfd..cb821cdb2a 100644 --- a/packages/nodes-base/nodes/Chargebee/Chargebee.node.ts +++ b/packages/nodes-base/nodes/Chargebee/Chargebee.node.ts @@ -488,7 +488,7 @@ export class Chargebee implements INodeType { const returnData: IDataObject[] = []; let item: INodeExecutionData; - const credentials = this.getCredentials('chargebeeApi'); + const credentials = await this.getCredentials('chargebeeApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts b/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts index 3e40012303..171dff05b2 100644 --- a/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/CircleCi/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function circleciApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('circleCiApi'); + const credentials = await this.getCredentials('circleCiApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Cisco/Webex/CiscoWebexTrigger.node.ts b/packages/nodes-base/nodes/Cisco/Webex/CiscoWebexTrigger.node.ts index 7a33970f1c..950263b2cb 100644 --- a/packages/nodes-base/nodes/Cisco/Webex/CiscoWebexTrigger.node.ts +++ b/packages/nodes-base/nodes/Cisco/Webex/CiscoWebexTrigger.node.ts @@ -8,6 +8,7 @@ import { INodeType, INodeTypeDescription, IWebhookResponseData, + NodeOperationError, } from 'n8n-workflow'; import { @@ -600,7 +601,11 @@ export class CiscoWebexTrigger implements INodeType { const event = this.getNodeParameter('event') as string; const resource = this.getNodeParameter('resource') as string; const filters = this.getNodeParameter('filters', {}) as IDataObject; - const secret = getAutomaticSecret(this.getCredentials('ciscoWebexOAuth2Api')!); + const credentials = await this.getCredentials('ciscoWebexOAuth2Api'); + if (credentials === undefined) { + throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); + } + const secret = getAutomaticSecret(credentials); const filter = []; for (const key of Object.keys(filters)) { if (key !== 'ownedBy') { diff --git a/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts b/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts index 1dc18b0482..969adc91cc 100644 --- a/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts @@ -12,7 +12,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function clearbitApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, api: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('clearbitApi'); + const credentials = await this.getCredentials('clearbitApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts b/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts index 7213056fe8..50c1b1fb50 100644 --- a/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts @@ -34,7 +34,7 @@ export async function clickupApiRequest(this: IHookFunctions | IExecuteFunctions if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('clickUpApi'); + const credentials = await this.getCredentials('clickUpApi'); options.headers!['Authorization'] = credentials?.accessToken; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Clockify/GenericFunctions.ts b/packages/nodes-base/nodes/Clockify/GenericFunctions.ts index e8fc43e6c4..723a187a76 100644 --- a/packages/nodes-base/nodes/Clockify/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Clockify/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function clockifyApiRequest(this: ILoadOptionsFunctions | IPollFunctions | IExecuteFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('clockifyApi'); + const credentials = await this.getCredentials('clockifyApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Cockpit/GenericFunctions.ts b/packages/nodes-base/nodes/Cockpit/GenericFunctions.ts index 5e34e76615..25ed70f399 100644 --- a/packages/nodes-base/nodes/Cockpit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Cockpit/GenericFunctions.ts @@ -7,7 +7,7 @@ import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; import { OptionsWithUri } from 'request'; export async function cockpitApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('cockpitApi'); + const credentials = await this.getCredentials('cockpitApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials available.'); diff --git a/packages/nodes-base/nodes/Coda/GenericFunctions.ts b/packages/nodes-base/nodes/Coda/GenericFunctions.ts index 2dd7691150..92b1cf1ad9 100644 --- a/packages/nodes-base/nodes/Coda/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Coda/GenericFunctions.ts @@ -7,7 +7,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function codaApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('codaApi'); + const credentials = await this.getCredentials('codaApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Contentful/Contentful.node.ts b/packages/nodes-base/nodes/Contentful/Contentful.node.ts index d5b2ff70dc..efbd1bb779 100644 --- a/packages/nodes-base/nodes/Contentful/Contentful.node.ts +++ b/packages/nodes-base/nodes/Contentful/Contentful.node.ts @@ -105,7 +105,7 @@ export class Contentful implements INodeType { if (resource === 'space') { if (operation === 'get') { - const credentials = this.getCredentials('contentfulApi'); + const credentials = await this.getCredentials('contentfulApi'); responseData = await contentfulApiRequest.call(this, 'GET', `/spaces/${credentials?.spaceId}`); } @@ -113,7 +113,7 @@ export class Contentful implements INodeType { if (resource === 'contentType') { if (operation === 'get') { - const credentials = this.getCredentials('contentfulApi'); + const credentials = await this.getCredentials('contentfulApi'); const env = this.getNodeParameter('environmentId', 0) as string; @@ -132,7 +132,7 @@ export class Contentful implements INodeType { if (operation === 'get') { - const credentials = this.getCredentials('contentfulApi'); + const credentials = await this.getCredentials('contentfulApi'); const env = this.getNodeParameter('environmentId', 0) as string; @@ -147,7 +147,7 @@ export class Contentful implements INodeType { } } else if (operation === 'getAll') { - const credentials = this.getCredentials('contentfulApi'); + const credentials = await this.getCredentials('contentfulApi'); const returnAll = this.getNodeParameter('returnAll', 0) as boolean; @@ -214,7 +214,7 @@ export class Contentful implements INodeType { if (resource === 'asset') { if (operation === 'get') { - const credentials = this.getCredentials('contentfulApi'); + const credentials = await this.getCredentials('contentfulApi'); const env = this.getNodeParameter('environmentId', 0) as string; @@ -230,7 +230,7 @@ export class Contentful implements INodeType { } else if (operation === 'getAll') { - const credentials = this.getCredentials('contentfulApi'); + const credentials = await this.getCredentials('contentfulApi'); const returnAll = this.getNodeParameter('returnAll', 0) as boolean; @@ -298,7 +298,7 @@ export class Contentful implements INodeType { if (operation === 'getAll') { - const credentials = this.getCredentials('contentfulApi'); + const credentials = await this.getCredentials('contentfulApi'); const returnAll = this.getNodeParameter('returnAll', 0) as boolean; diff --git a/packages/nodes-base/nodes/Contentful/GenericFunctions.ts b/packages/nodes-base/nodes/Contentful/GenericFunctions.ts index 24cf806560..75ca5beb65 100644 --- a/packages/nodes-base/nodes/Contentful/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Contentful/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function contentfulApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('contentfulApi'); + const credentials = await this.getCredentials('contentfulApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/ConvertKit/GenericFunctions.ts b/packages/nodes-base/nodes/ConvertKit/GenericFunctions.ts index 50741c267a..02aed42ecf 100644 --- a/packages/nodes-base/nodes/ConvertKit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ConvertKit/GenericFunctions.ts @@ -18,7 +18,7 @@ import { export async function convertKitApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IHookFunctions, method: string, endpoint: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('convertKitApi'); + const credentials = await this.getCredentials('convertKitApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts b/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts index eaf48ed1ee..341a8f9589 100644 --- a/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts +++ b/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts @@ -133,7 +133,7 @@ export class CopperTrigger implements INodeType { event, }; - const credentials = this.getCredentials('copperApi'); + const credentials = await this.getCredentials('copperApi'); body.secret = { secret: getAutomaticSecret(credentials!), }; @@ -157,7 +157,7 @@ export class CopperTrigger implements INodeType { }; async webhook(this: IWebhookFunctions): Promise { - const credentials = this.getCredentials('copperApi'); + const credentials = await this.getCredentials('copperApi'); const req = this.getRequestObject(); // Check if the supplied secret matches. If not ignore request. diff --git a/packages/nodes-base/nodes/Copper/GenericFunctions.ts b/packages/nodes-base/nodes/Copper/GenericFunctions.ts index 8d91f53285..85d2a028ad 100644 --- a/packages/nodes-base/nodes/Copper/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Copper/GenericFunctions.ts @@ -44,7 +44,7 @@ export async function copperApiRequest( uri = '', option: IDataObject = {}, ) { - const credentials = this.getCredentials('copperApi') as { apiKey: string, email: string }; + const credentials = await this.getCredentials('copperApi') as { apiKey: string, email: string }; let options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Cortex/GenericFunctions.ts b/packages/nodes-base/nodes/Cortex/GenericFunctions.ts index a44837b77f..d532d9d432 100644 --- a/packages/nodes-base/nodes/Cortex/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Cortex/GenericFunctions.ts @@ -23,7 +23,7 @@ import * as moment from 'moment'; export async function cortexApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('cortexApi'); + const credentials = await this.getCredentials('cortexApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/CrateDb/CrateDb.node.ts b/packages/nodes-base/nodes/CrateDb/CrateDb.node.ts index 659001eec1..26c7f80da1 100644 --- a/packages/nodes-base/nodes/CrateDb/CrateDb.node.ts +++ b/packages/nodes-base/nodes/CrateDb/CrateDb.node.ts @@ -256,7 +256,7 @@ export class CrateDb implements INodeType { }; async execute(this: IExecuteFunctions): Promise { - const credentials = this.getCredentials('crateDb'); + const credentials = await this.getCredentials('crateDb'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts b/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts index 609baeb52d..fdebdcd5fd 100644 --- a/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts @@ -17,7 +17,7 @@ import { } from 'lodash'; export async function customerIoApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, baseApi?: string, query?: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('customerIoApi'); + const credentials = await this.getCredentials('customerIoApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/DeepL/GenericFunctions.ts b/packages/nodes-base/nodes/DeepL/GenericFunctions.ts index 99b4a96132..fa1c93e0d2 100644 --- a/packages/nodes-base/nodes/DeepL/GenericFunctions.ts +++ b/packages/nodes-base/nodes/DeepL/GenericFunctions.ts @@ -25,7 +25,7 @@ export async function deepLApiRequest( const proApiEndpoint = 'https://api.deepl.com/v2'; const freeApiEndpoint = 'https://api-free.deepl.com/v2'; - const credentials = this.getCredentials('deepLApi'); + const credentials = await this.getCredentials('deepLApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -51,6 +51,12 @@ export async function deepLApiRequest( delete options.body; } + const credentials = await this.getCredentials('deepLApi'); + + if (credentials === undefined) { + throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); + } + options.qs.auth_key = credentials.apiKey; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Demio/GenericFunctions.ts b/packages/nodes-base/nodes/Demio/GenericFunctions.ts index 04b7a9d6cc..4ad71c5d63 100644 --- a/packages/nodes-base/nodes/Demio/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Demio/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function demioApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { - const credentials = this.getCredentials('demioApi'); + const credentials = await this.getCredentials('demioApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Discourse/GenericFunctions.ts b/packages/nodes-base/nodes/Discourse/GenericFunctions.ts index a5c5acd55e..2532280d60 100644 --- a/packages/nodes-base/nodes/Discourse/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Discourse/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function discourseApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('discourseApi') as IDataObject; + const credentials = await this.getCredentials('discourseApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Disqus/GenericFunctions.ts b/packages/nodes-base/nodes/Disqus/GenericFunctions.ts index 2b1414989c..eb994e07a0 100644 --- a/packages/nodes-base/nodes/Disqus/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Disqus/GenericFunctions.ts @@ -16,7 +16,7 @@ export async function disqusApiRequest( option: IDataObject = {}, ): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('disqusApi') as IDataObject; + const credentials = await this.getCredentials('disqusApi') as IDataObject; qs.api_key = credentials.accessToken; if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Drift/GenericFunctions.ts b/packages/nodes-base/nodes/Drift/GenericFunctions.ts index 9b288c04eb..8687a4f835 100644 --- a/packages/nodes-base/nodes/Drift/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Drift/GenericFunctions.ts @@ -35,7 +35,7 @@ export async function driftApiRequest(this: IExecuteFunctions | IWebhookFunction try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('driftApi'); + const credentials = await this.getCredentials('driftApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Dropbox/Dropbox.node.ts b/packages/nodes-base/nodes/Dropbox/Dropbox.node.ts index 383402e0ee..3f2e95ec14 100644 --- a/packages/nodes-base/nodes/Dropbox/Dropbox.node.ts +++ b/packages/nodes-base/nodes/Dropbox/Dropbox.node.ts @@ -796,7 +796,7 @@ export class Dropbox implements INodeType { let simple = false; - const { accessType } = getCredentials.call(this); + const { accessType } = await getCredentials.call(this); if (accessType === 'full') { // get the root directory to set it as the default for all operations diff --git a/packages/nodes-base/nodes/Dropbox/GenericFunctions.ts b/packages/nodes-base/nodes/Dropbox/GenericFunctions.ts index caf476bee9..e5053cbfef 100644 --- a/packages/nodes-base/nodes/Dropbox/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Dropbox/GenericFunctions.ts @@ -42,7 +42,7 @@ export async function dropboxApiRequest(this: IHookFunctions | IExecuteFunctions try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('dropboxApi') as IDataObject; + const credentials = await this.getCredentials('dropboxApi') as IDataObject; options.headers!['Authorization'] = `Bearer ${credentials.accessToken}`; @@ -101,12 +101,12 @@ export function simplify(data: IDataObject[]) { return results; } -export function getCredentials(this: IExecuteFunctions) { +export async function getCredentials(this: IExecuteFunctions) { const authenticationMethod = this.getNodeParameter('authentication', 0) as string; if (authenticationMethod === 'accessToken') { - return this.getCredentials('dropboxApi') as IDataObject; + return await this.getCredentials('dropboxApi') as IDataObject; } else { - return this.getCredentials('dropboxOAuth2Api') as IDataObject; + return await this.getCredentials('dropboxOAuth2Api') as IDataObject; } } diff --git a/packages/nodes-base/nodes/ERPNext/GenericFunctions.ts b/packages/nodes-base/nodes/ERPNext/GenericFunctions.ts index 4a85c0064a..72d1d67e4e 100644 --- a/packages/nodes-base/nodes/ERPNext/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ERPNext/GenericFunctions.ts @@ -24,7 +24,7 @@ export async function erpNextApiRequest( uri?: string, option: IDataObject = {}, ) { - const credentials = this.getCredentials('erpNextApi') as ERPNextApiCredentials; + const credentials = await this.getCredentials('erpNextApi') as ERPNextApiCredentials; const baseUrl = getBaseUrl(credentials); if (credentials === undefined) { diff --git a/packages/nodes-base/nodes/Egoi/GenericFunctions.ts b/packages/nodes-base/nodes/Egoi/GenericFunctions.ts index e7447d9084..41c1cade6a 100644 --- a/packages/nodes-base/nodes/Egoi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Egoi/GenericFunctions.ts @@ -35,7 +35,7 @@ export async function getFields(this: IExecuteFunctions, listId: string) { export async function egoiApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, qs: IDataObject = {}, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('egoiApi') as IDataObject; + const credentials = await this.getCredentials('egoiApi') as IDataObject; const options: OptionsWithUrl = { headers: { diff --git a/packages/nodes-base/nodes/Elasticsearch/GenericFunctions.ts b/packages/nodes-base/nodes/Elasticsearch/GenericFunctions.ts index 9fc7a9844b..bfcd96faeb 100644 --- a/packages/nodes-base/nodes/Elasticsearch/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Elasticsearch/GenericFunctions.ts @@ -26,7 +26,7 @@ export async function elasticsearchApiRequest( username, password, baseUrl, - } = this.getCredentials('elasticsearchApi') as ElasticsearchApiCredentials; + } = await this.getCredentials('elasticsearchApi') as ElasticsearchApiCredentials; const token = Buffer.from(`${username}:${password}`).toString('base64'); diff --git a/packages/nodes-base/nodes/EmailReadImap.node.ts b/packages/nodes-base/nodes/EmailReadImap.node.ts index 1a046287b1..d07c2b5a9c 100644 --- a/packages/nodes-base/nodes/EmailReadImap.node.ts +++ b/packages/nodes-base/nodes/EmailReadImap.node.ts @@ -177,7 +177,7 @@ export class EmailReadImap implements INodeType { async trigger(this: ITriggerFunctions): Promise { - const credentials = this.getCredentials('imap'); + const credentials = await this.getCredentials('imap'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/EmailSend.node.ts b/packages/nodes-base/nodes/EmailSend.node.ts index 701f42c912..2c9a5e309f 100644 --- a/packages/nodes-base/nodes/EmailSend.node.ts +++ b/packages/nodes-base/nodes/EmailSend.node.ts @@ -147,7 +147,7 @@ export class EmailSend implements INodeType { const attachmentPropertyString = this.getNodeParameter('attachments', itemIndex) as string; const options = this.getNodeParameter('options', itemIndex, {}) as IDataObject; - const credentials = this.getCredentials('smtp'); + const credentials = await this.getCredentials('smtp'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Emelia/GenericFunctions.ts b/packages/nodes-base/nodes/Emelia/GenericFunctions.ts index 916da27c98..745dcd5228 100644 --- a/packages/nodes-base/nodes/Emelia/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Emelia/GenericFunctions.ts @@ -35,7 +35,7 @@ export async function emeliaApiRequest( body: object = {}, qs: object = {}, ) { - const { apiKey } = this.getCredentials('emeliaApi') as { apiKey: string }; + const { apiKey } = await this.getCredentials('emeliaApi') as { apiKey: string }; const options = { headers: { diff --git a/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts b/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts index 8490896b1e..ef1f623b93 100644 --- a/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Eventbrite/GenericFunctions.ts @@ -32,7 +32,7 @@ export async function eventbriteApiRequest(this: IHookFunctions | IExecuteFuncti try { if (authenticationMethod === 'privateKey') { - const credentials = this.getCredentials('eventbriteApi'); + const credentials = await this.getCredentials('eventbriteApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Facebook/FacebookGraphApi.node.ts b/packages/nodes-base/nodes/Facebook/FacebookGraphApi.node.ts index 0e73c19863..d8109e7f5a 100644 --- a/packages/nodes-base/nodes/Facebook/FacebookGraphApi.node.ts +++ b/packages/nodes-base/nodes/Facebook/FacebookGraphApi.node.ts @@ -295,7 +295,7 @@ export class FacebookGraphApi implements INodeType { const returnItems: INodeExecutionData[] = []; for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { - const graphApiCredentials = this.getCredentials('facebookGraphApi'); + const graphApiCredentials = await this.getCredentials('facebookGraphApi'); const hostUrl = this.getNodeParameter('hostUrl', itemIndex) as string; const httpRequestMethod = this.getNodeParameter('httpRequestMethod', itemIndex) as string; diff --git a/packages/nodes-base/nodes/Facebook/FacebookTrigger.node.ts b/packages/nodes-base/nodes/Facebook/FacebookTrigger.node.ts index 7e0977ba54..92ec4e38da 100644 --- a/packages/nodes-base/nodes/Facebook/FacebookTrigger.node.ts +++ b/packages/nodes-base/nodes/Facebook/FacebookTrigger.node.ts @@ -248,7 +248,7 @@ export class FacebookTrigger implements INodeType { const res = this.getResponseObject(); const req = this.getRequestObject(); const headerData = this.getHeaderData() as IDataObject; - const credentials = this.getCredentials('facebookGraphAppApi') as IDataObject; + const credentials = await this.getCredentials('facebookGraphAppApi') as IDataObject; // Check if we're getting facebook's challenge request (https://developers.facebook.com/docs/graph-api/webhooks/getting-started) if (this.getWebhookName() === 'setup') { if (query['hub.challenge']) { diff --git a/packages/nodes-base/nodes/Facebook/GenericFunctions.ts b/packages/nodes-base/nodes/Facebook/GenericFunctions.ts index c80a12c574..b25d8c1955 100644 --- a/packages/nodes-base/nodes/Facebook/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Facebook/GenericFunctions.ts @@ -23,9 +23,9 @@ export async function facebookApiRequest(this: IHookFunctions | IExecuteFunction let credentials; if (this.getNode().name.includes('Trigger')) { - credentials = this.getCredentials('facebookGraphAppApi') as IDataObject; + credentials = await this.getCredentials('facebookGraphAppApi') as IDataObject; } else { - credentials = this.getCredentials('facebookGraphApi') as IDataObject; + credentials = await this.getCredentials('facebookGraphApi') as IDataObject; } qs.access_token = credentials!.accessToken; diff --git a/packages/nodes-base/nodes/FileMaker/FileMaker.node.ts b/packages/nodes-base/nodes/FileMaker/FileMaker.node.ts index 8ddd3c2bc0..fcab16abbd 100644 --- a/packages/nodes-base/nodes/FileMaker/FileMaker.node.ts +++ b/packages/nodes-base/nodes/FileMaker/FileMaker.node.ts @@ -773,7 +773,7 @@ export class FileMaker implements INodeType { const items = this.getInputData(); const returnData: INodeExecutionData[] = []; - const credentials = this.getCredentials('fileMaker'); + const credentials = await this.getCredentials('fileMaker'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/FileMaker/GenericFunctions.ts b/packages/nodes-base/nodes/FileMaker/GenericFunctions.ts index f2f979cb5f..db2b4711ac 100644 --- a/packages/nodes-base/nodes/FileMaker/GenericFunctions.ts +++ b/packages/nodes-base/nodes/FileMaker/GenericFunctions.ts @@ -39,7 +39,7 @@ interface ScriptObject { */ export async function layoutsApiRequest(this: ILoadOptionsFunctions | IExecuteFunctions | IExecuteSingleFunctions): Promise { // tslint:disable-line:no-any const token = await getToken.call(this); - const credentials = this.getCredentials('fileMaker'); + const credentials = await this.getCredentials('fileMaker'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -89,7 +89,7 @@ function parseLayouts(layouts: LayoutObject[]): INodePropertyOptions[] { */ export async function getFields(this: ILoadOptionsFunctions): Promise { // tslint:disable-line:no-any const token = await getToken.call(this); - const credentials = this.getCredentials('fileMaker'); + const credentials = await this.getCredentials('fileMaker'); const layout = this.getCurrentNodeParameter('layout') as string; if (credentials === undefined) { @@ -125,7 +125,7 @@ export async function getFields(this: ILoadOptionsFunctions): Promise { // */ export async function getPortals(this: ILoadOptionsFunctions): Promise { // tslint:disable-line:no-any const token = await getToken.call(this); - const credentials = this.getCredentials('fileMaker'); + const credentials = await this.getCredentials('fileMaker'); const layout = this.getCurrentNodeParameter('layout') as string; if (credentials === undefined) { @@ -161,7 +161,7 @@ export async function getPortals(this: ILoadOptionsFunctions): Promise { // */ export async function getScripts(this: ILoadOptionsFunctions): Promise { // tslint:disable-line:no-any const token = await getToken.call(this); - const credentials = this.getCredentials('fileMaker'); + const credentials = await this.getCredentials('fileMaker'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -207,7 +207,7 @@ function parseScriptsList(scripts: ScriptObject[]): INodePropertyOptions[] { } export async function getToken(this: ILoadOptionsFunctions | IExecuteFunctions | IExecuteSingleFunctions): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('fileMaker'); + const credentials = await this.getCredentials('fileMaker'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } @@ -256,7 +256,7 @@ export async function getToken(this: ILoadOptionsFunctions | IExecuteFunctions | } export async function logout(this: ILoadOptionsFunctions | IExecuteFunctions | IExecuteSingleFunctions, token: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('fileMaker'); + const credentials = await this.getCredentials('fileMaker'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Flow/Flow.node.ts b/packages/nodes-base/nodes/Flow/Flow.node.ts index 79bc09f985..521957d6a1 100644 --- a/packages/nodes-base/nodes/Flow/Flow.node.ts +++ b/packages/nodes-base/nodes/Flow/Flow.node.ts @@ -63,7 +63,7 @@ export class Flow implements INodeType { }; async execute(this: IExecuteFunctions): Promise { - const credentials = this.getCredentials('flowApi'); + const credentials = await this.getCredentials('flowApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Flow/FlowTrigger.node.ts b/packages/nodes-base/nodes/Flow/FlowTrigger.node.ts index 062dbe1630..f0a30c631e 100644 --- a/packages/nodes-base/nodes/Flow/FlowTrigger.node.ts +++ b/packages/nodes-base/nodes/Flow/FlowTrigger.node.ts @@ -109,7 +109,7 @@ export class FlowTrigger implements INodeType { webhookMethods = { default: { async checkExists(this: IHookFunctions): Promise { - const credentials = this.getCredentials('flowApi'); + const credentials = await this.getCredentials('flowApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -143,7 +143,7 @@ export class FlowTrigger implements INodeType { return true; }, async create(this: IHookFunctions): Promise { - const credentials = this.getCredentials('flowApi'); + const credentials = await this.getCredentials('flowApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -187,7 +187,7 @@ export class FlowTrigger implements INodeType { return true; }, async delete(this: IHookFunctions): Promise { - const credentials = this.getCredentials('flowApi'); + const credentials = await this.getCredentials('flowApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Flow/GenericFunctions.ts b/packages/nodes-base/nodes/Flow/GenericFunctions.ts index 447d9eca06..cf5b395165 100644 --- a/packages/nodes-base/nodes/Flow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Flow/GenericFunctions.ts @@ -8,7 +8,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function flowApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('flowApi'); + const credentials = await this.getCredentials('flowApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts b/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts index dea3ef15a0..4c54b6cefe 100644 --- a/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function freshdeskApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('freshdeskApi'); + const credentials = await this.getCredentials('freshdeskApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/FreshworksCrm/GenericFunctions.ts b/packages/nodes-base/nodes/FreshworksCrm/GenericFunctions.ts index b7d27d093b..25ec4f0d87 100644 --- a/packages/nodes-base/nodes/FreshworksCrm/GenericFunctions.ts +++ b/packages/nodes-base/nodes/FreshworksCrm/GenericFunctions.ts @@ -31,7 +31,7 @@ export async function freshworksCrmApiRequest( body: IDataObject = {}, qs: IDataObject = {}, ) { - const { apiKey, domain } = this.getCredentials('freshworksCrmApi') as FreshworksCrmApiCredentials; + const { apiKey, domain } = await this.getCredentials('freshworksCrmApi') as FreshworksCrmApiCredentials; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Ftp.node.ts b/packages/nodes-base/nodes/Ftp.node.ts index 9540f33c3c..8e888f8612 100644 --- a/packages/nodes-base/nodes/Ftp.node.ts +++ b/packages/nodes-base/nodes/Ftp.node.ts @@ -374,9 +374,9 @@ export class Ftp implements INodeType { const protocol = this.getNodeParameter('protocol', 0) as string; if (protocol === 'sftp') { - credentials = this.getCredentials('sftp'); + credentials = await this.getCredentials('sftp'); } else { - credentials = this.getCredentials('ftp'); + credentials = await this.getCredentials('ftp'); } try { diff --git a/packages/nodes-base/nodes/GetResponse/GenericFunctions.ts b/packages/nodes-base/nodes/GetResponse/GenericFunctions.ts index a0c8119f36..13d38c7d04 100644 --- a/packages/nodes-base/nodes/GetResponse/GenericFunctions.ts +++ b/packages/nodes-base/nodes/GetResponse/GenericFunctions.ts @@ -34,7 +34,7 @@ export async function getresponseApiRequest(this: IWebhookFunctions | IHookFunct } if (authentication === 'apiKey') { - const credentials = this.getCredentials('getResponseApi') as IDataObject; + const credentials = await this.getCredentials('getResponseApi') as IDataObject; options!.headers!['X-Auth-Token'] = `api-key ${credentials.apiKey}`; //@ts-ignore return await this.helpers.request.call(this, options); diff --git a/packages/nodes-base/nodes/Ghost/GenericFunctions.ts b/packages/nodes-base/nodes/Ghost/GenericFunctions.ts index c1a83bf2c3..15b93bac21 100644 --- a/packages/nodes-base/nodes/Ghost/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Ghost/GenericFunctions.ts @@ -26,11 +26,11 @@ export async function ghostApiRequest(this: IHookFunctions | IExecuteFunctions | if (source === 'contentApi') { //https://ghost.org/faq/api-versioning/ version = 'v3'; - credentials = this.getCredentials('ghostContentApi') as IDataObject; + credentials = await this.getCredentials('ghostContentApi') as IDataObject; query.key = credentials.apiKey as string; } else { version = 'v2'; - credentials = this.getCredentials('ghostAdminApi') as IDataObject; + credentials = await this.getCredentials('ghostAdminApi') as IDataObject; // Create the token (including decoding secret) const [id, secret] = (credentials.apiKey as string).split(':'); diff --git a/packages/nodes-base/nodes/Git/Git.node.ts b/packages/nodes-base/nodes/Git/Git.node.ts index f4e6ef4b16..6b3c795eb1 100644 --- a/packages/nodes-base/nodes/Git/Git.node.ts +++ b/packages/nodes-base/nodes/Git/Git.node.ts @@ -206,11 +206,11 @@ export class Git implements INodeType { const items = this.getInputData(); - const prepareRepository = (repositoryPath: string): string => { + const prepareRepository = async (repositoryPath: string): Promise => { const authentication = this.getNodeParameter('authentication', 0) as string; if (authentication === 'gitPassword') { - const gitCredentials = this.getCredentials('gitPassword') as IDataObject; + const gitCredentials = await this.getCredentials('gitPassword') as IDataObject; const url = new URL(repositoryPath); url.username = gitCredentials.username as string; @@ -284,7 +284,7 @@ export class Git implements INodeType { // ---------------------------------- let sourceRepository = this.getNodeParameter('sourceRepository', itemIndex, '') as string; - sourceRepository = prepareRepository(sourceRepository); + sourceRepository = await prepareRepository(sourceRepository); await git.clone(sourceRepository, '.'); @@ -348,7 +348,7 @@ export class Git implements INodeType { // ---------------------------------- if (options.repository) { - const targetRepository = prepareRepository(options.targetRepository as string); + const targetRepository = await prepareRepository(options.targetRepository as string); await git.push(targetRepository); } else { const authentication = this.getNodeParameter('authentication', 0) as string; @@ -364,7 +364,7 @@ export class Git implements INodeType { } } - targetRepository = prepareRepository(targetRepository as string); + targetRepository = await prepareRepository(targetRepository as string); await git.push(targetRepository); } else { await git.push(); diff --git a/packages/nodes-base/nodes/Github/GenericFunctions.ts b/packages/nodes-base/nodes/Github/GenericFunctions.ts index 4b1ec4d6c5..f5bfcf0d50 100644 --- a/packages/nodes-base/nodes/Github/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Github/GenericFunctions.ts @@ -39,7 +39,7 @@ export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions, const authenticationMethod = this.getNodeParameter('authentication', 0, 'accessToken') as string; if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('githubApi'); + const credentials = await this.getCredentials('githubApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } @@ -50,7 +50,7 @@ export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions, options.headers!.Authorization = `token ${credentials.accessToken}`; return await this.helpers.request(options); } else { - const credentials = this.getCredentials('githubOAuth2Api'); + const credentials = await this.getCredentials('githubOAuth2Api'); const baseUrl = credentials!.server || 'https://api.github.com'; options.uri = `${baseUrl}${endpoint}`; diff --git a/packages/nodes-base/nodes/Gitlab/GenericFunctions.ts b/packages/nodes-base/nodes/Gitlab/GenericFunctions.ts index 6f50af91ba..ba73e7dfe3 100644 --- a/packages/nodes-base/nodes/Gitlab/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Gitlab/GenericFunctions.ts @@ -39,7 +39,7 @@ export async function gitlabApiRequest(this: IHookFunctions | IExecuteFunctions, try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('gitlabApi'); + const credentials = await this.getCredentials('gitlabApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } @@ -50,7 +50,7 @@ export async function gitlabApiRequest(this: IHookFunctions | IExecuteFunctions, return await this.helpers.request(options); } else { - const credentials = this.getCredentials('gitlabOAuth2Api'); + const credentials = await this.getCredentials('gitlabOAuth2Api'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts b/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts index dda2651879..26546b4230 100644 --- a/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts +++ b/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts @@ -1101,13 +1101,13 @@ export class Gitlab implements INodeType { try { if (authenticationMethod === 'accessToken') { - credentials = this.getCredentials('gitlabApi'); + credentials = await this.getCredentials('gitlabApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } } else { - credentials = this.getCredentials('gitlabOAuth2Api'); + credentials = await this.getCredentials('gitlabOAuth2Api'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/GoToWebinar/GenericFunctions.ts b/packages/nodes-base/nodes/GoToWebinar/GenericFunctions.ts index c28a0217c1..82bdf928b3 100644 --- a/packages/nodes-base/nodes/GoToWebinar/GenericFunctions.ts +++ b/packages/nodes-base/nodes/GoToWebinar/GenericFunctions.ts @@ -137,7 +137,7 @@ export async function handleGetAll( } export async function loadWebinars(this: ILoadOptionsFunctions) { - const { oauthTokenData } = this.getCredentials('goToWebinarOAuth2Api') as { + const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as { oauthTokenData: { account_key: string } }; @@ -163,7 +163,7 @@ export async function loadWebinars(this: ILoadOptionsFunctions) { } export async function loadWebinarSessions(this: ILoadOptionsFunctions) { - const { oauthTokenData } = this.getCredentials('goToWebinarOAuth2Api') as { + const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as { oauthTokenData: { organizer_key: string } }; @@ -186,7 +186,7 @@ export async function loadWebinarSessions(this: ILoadOptionsFunctions) { } export async function loadRegistranSimpleQuestions(this: ILoadOptionsFunctions) { - const { oauthTokenData } = this.getCredentials('goToWebinarOAuth2Api') as { + const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as { oauthTokenData: { organizer_key: string } }; @@ -211,7 +211,7 @@ export async function loadRegistranSimpleQuestions(this: ILoadOptionsFunctions) } export async function loadAnswers(this: ILoadOptionsFunctions) { - const { oauthTokenData } = this.getCredentials('goToWebinarOAuth2Api') as { + const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as { oauthTokenData: { organizer_key: string } }; @@ -240,7 +240,7 @@ export async function loadAnswers(this: ILoadOptionsFunctions) { } export async function loadRegistranMultiChoiceQuestions(this: ILoadOptionsFunctions) { - const { oauthTokenData } = this.getCredentials('goToWebinarOAuth2Api') as { + const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as { oauthTokenData: { organizer_key: string } }; diff --git a/packages/nodes-base/nodes/GoToWebinar/GoToWebinar.node.ts b/packages/nodes-base/nodes/GoToWebinar/GoToWebinar.node.ts index 409ce68cca..2b8b35f415 100644 --- a/packages/nodes-base/nodes/GoToWebinar/GoToWebinar.node.ts +++ b/packages/nodes-base/nodes/GoToWebinar/GoToWebinar.node.ts @@ -158,7 +158,7 @@ export class GoToWebinar implements INodeType { let responseData; const returnData: IDataObject[] = []; - const { oauthTokenData } = this.getCredentials('goToWebinarOAuth2Api') as { + const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as { oauthTokenData: { account_key: string, organizer_key: string } }; diff --git a/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts index b05c17f4b0..830eff470c 100644 --- a/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts @@ -37,7 +37,7 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF } if (authenticationMethod === 'serviceAccount') { - const credentials = this.getCredentials('googleApi'); + const credentials = await this.getCredentials('googleApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts index c232921f51..736845d2dc 100644 --- a/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts @@ -44,7 +44,7 @@ export async function googleApiRequest( try { if (authenticationMethod === 'serviceAccount') { - const credentials = this.getCredentials('googleApi'); + const credentials = await this.getCredentials('googleApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts index e48779ddce..726b533655 100644 --- a/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts @@ -36,7 +36,7 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF } if (authenticationMethod === 'serviceAccount') { - const credentials = this.getCredentials('googleApi'); + const credentials = await this.getCredentials('googleApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Google/Drive/GoogleDriveTrigger.node.ts b/packages/nodes-base/nodes/Google/Drive/GoogleDriveTrigger.node.ts index e594b4656e..c917e64874 100644 --- a/packages/nodes-base/nodes/Google/Drive/GoogleDriveTrigger.node.ts +++ b/packages/nodes-base/nodes/Google/Drive/GoogleDriveTrigger.node.ts @@ -98,7 +98,7 @@ // const resourceId = this.getNodeParameter('resourceId') as string; -// const credentials = this.getCredentials('googleApi'); +// const credentials = await this.getCredentials('googleApi'); // if (credentials === undefined) { // throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -190,7 +190,7 @@ // const resourceId = this.getNodeParameter('resourceId') as string; -// const credentials = this.getCredentials('googleApi'); +// const credentials = await this.getCredentials('googleApi'); // if (credentials === undefined) { // throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts index d76dd48d28..3301d5731f 100644 --- a/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts @@ -57,7 +57,7 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF } if (authenticationMethod === 'serviceAccount') { - const credentials = this.getCredentials('googleApi'); + const credentials = await this.getCredentials('googleApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Google/Sheet/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Sheet/GenericFunctions.ts index 1e6f03e98f..225967d448 100644 --- a/packages/nodes-base/nodes/Google/Sheet/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Sheet/GenericFunctions.ts @@ -37,7 +37,7 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF } if (authenticationMethod === 'serviceAccount') { - const credentials = this.getCredentials('googleApi'); + const credentials = await this.getCredentials('googleApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts index 647db06dc6..245cc2467a 100644 --- a/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts @@ -45,7 +45,7 @@ export async function googleApiRequest( try { if (authenticationMethod === 'serviceAccount') { - const credentials = this.getCredentials('googleApi') as { access_token: string, email: string, privateKey: string }; + const credentials = await this.getCredentials('googleApi') as { access_token: string, email: string, privateKey: string }; const { access_token } = await getAccessToken.call(this, credentials); options.headers.Authorization = `Bearer ${access_token}`; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts index bd295e84c4..ec5bbaf273 100644 --- a/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts @@ -37,7 +37,7 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF } if (authenticationMethod === 'serviceAccount') { - const credentials = this.getCredentials('googleApi'); + const credentials = await this.getCredentials('googleApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Gotify/GenericFunctions.ts b/packages/nodes-base/nodes/Gotify/GenericFunctions.ts index 318f159ee4..e1d8bdca9b 100644 --- a/packages/nodes-base/nodes/Gotify/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Gotify/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function gotifyApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, uri?: string | undefined, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('gotifyApi') as IDataObject; + const credentials = await this.getCredentials('gotifyApi') as IDataObject; const options: OptionsWithUri = { method, diff --git a/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts b/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts index 346ed4c547..9d5391dcc2 100644 --- a/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts +++ b/packages/nodes-base/nodes/GraphQL/GraphQL.node.ts @@ -230,7 +230,7 @@ export class GraphQL implements INodeType { async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); - const httpHeaderAuth = this.getCredentials('httpHeaderAuth'); + const httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); let requestOptions: OptionsWithUri & RequestPromiseOptions; diff --git a/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts b/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts index 48dc63528c..412ea18c9c 100644 --- a/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts @@ -9,7 +9,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function gumroadApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('gumroadApi'); + const credentials = await this.getCredentials('gumroadApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Harvest/GenericFunctions.ts b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts index 67da0a7eb6..8d074aef25 100644 --- a/packages/nodes-base/nodes/Harvest/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Harvest/GenericFunctions.ts @@ -35,7 +35,7 @@ export async function harvestApiRequest(this: IHookFunctions | IExecuteFunctions try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('harvestApi') as IDataObject; + const credentials = await this.getCredentials('harvestApi') as IDataObject; if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/HomeAssistant/GenericFunctions.ts b/packages/nodes-base/nodes/HomeAssistant/GenericFunctions.ts index a4e6b3f9d5..796b03ee51 100644 --- a/packages/nodes-base/nodes/HomeAssistant/GenericFunctions.ts +++ b/packages/nodes-base/nodes/HomeAssistant/GenericFunctions.ts @@ -13,7 +13,7 @@ import { } from 'n8n-workflow'; export async function homeAssistantApiRequest(this: IExecuteFunctions, method: string, resource: string, body: IDataObject = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}) { - const credentials = this.getCredentials('homeAssistantApi'); + const credentials = await this.getCredentials('homeAssistantApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/HttpRequest.node.ts b/packages/nodes-base/nodes/HttpRequest.node.ts index a7aa3db464..563c53490c 100644 --- a/packages/nodes-base/nodes/HttpRequest.node.ts +++ b/packages/nodes-base/nodes/HttpRequest.node.ts @@ -640,11 +640,11 @@ export class HttpRequest implements INodeType { const parametersAreJson = this.getNodeParameter('jsonParameters', 0) as boolean; const responseFormat = this.getNodeParameter('responseFormat', 0) as string; - const httpBasicAuth = this.getCredentials('httpBasicAuth'); - const httpDigestAuth = this.getCredentials('httpDigestAuth'); - const httpHeaderAuth = this.getCredentials('httpHeaderAuth'); - const oAuth1Api = this.getCredentials('oAuth1Api'); - const oAuth2Api = this.getCredentials('oAuth2Api'); + const httpBasicAuth = await this.getCredentials('httpBasicAuth'); + const httpDigestAuth = await this.getCredentials('httpDigestAuth'); + const httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); + const oAuth1Api = await this.getCredentials('oAuth1Api'); + const oAuth2Api = await this.getCredentials('oAuth2Api'); let requestOptions: OptionsWithUri; let setUiParameter: IDataObject; diff --git a/packages/nodes-base/nodes/Hubspot/GenericFunctions.ts b/packages/nodes-base/nodes/Hubspot/GenericFunctions.ts index b8fec59383..b430e54e3f 100644 --- a/packages/nodes-base/nodes/Hubspot/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Hubspot/GenericFunctions.ts @@ -33,13 +33,13 @@ export async function hubspotApiRequest(this: IHookFunctions | IExecuteFunctions try { if (authenticationMethod === 'apiKey') { - const credentials = this.getCredentials('hubspotApi'); + const credentials = await this.getCredentials('hubspotApi'); options.qs.hapikey = credentials!.apiKey as string; return await this.helpers.request!(options); } else if (authenticationMethod === 'developerApi') { - const credentials = this.getCredentials('hubspotDeveloperApi'); + const credentials = await this.getCredentials('hubspotDeveloperApi'); options.qs.hapikey = credentials!.apiKey as string; return await this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/Hubspot/HubspotTrigger.node.ts b/packages/nodes-base/nodes/Hubspot/HubspotTrigger.node.ts index d6224f3948..0551d9b184 100644 --- a/packages/nodes-base/nodes/Hubspot/HubspotTrigger.node.ts +++ b/packages/nodes-base/nodes/Hubspot/HubspotTrigger.node.ts @@ -277,7 +277,7 @@ export class HubspotTrigger implements INodeType { // Check all the webhooks which exist already if it is identical to the // one that is supposed to get created. const currentWebhookUrl = this.getNodeWebhookUrl('default') as string; - const { appId } = this.getCredentials('hubspotDeveloperApi') as IDataObject; + const { appId } = await this.getCredentials('hubspotDeveloperApi') as IDataObject; try { const { targetUrl } = await hubspotApiRequest.call(this, 'GET', `/webhooks/v3/${appId}/settings`, {}); @@ -304,7 +304,7 @@ export class HubspotTrigger implements INodeType { }, async create(this: IHookFunctions): Promise { const webhookUrl = this.getNodeWebhookUrl('default'); - const { appId } = this.getCredentials('hubspotDeveloperApi') as IDataObject; + const { appId } = await this.getCredentials('hubspotDeveloperApi') as IDataObject; const events = (this.getNodeParameter('eventsUi') as IDataObject || {}).eventValues as IDataObject[] || []; const additionalFields = this.getNodeParameter('additionalFields') as IDataObject; let endpoint = `/webhooks/v3/${appId}/settings`; @@ -336,7 +336,7 @@ export class HubspotTrigger implements INodeType { return true; }, async delete(this: IHookFunctions): Promise { - const { appId } = this.getCredentials('hubspotDeveloperApi') as IDataObject; + const { appId } = await this.getCredentials('hubspotDeveloperApi') as IDataObject; const { results: subscriptions } = await hubspotApiRequest.call(this, 'GET', `/webhooks/v3/${appId}/subscriptions`, {}); @@ -356,7 +356,7 @@ export class HubspotTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { - const credentials = this.getCredentials('hubspotDeveloperApi') as IDataObject; + const credentials = await this.getCredentials('hubspotDeveloperApi') as IDataObject; if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials found!'); diff --git a/packages/nodes-base/nodes/HumanticAI/GenericFunctions.ts b/packages/nodes-base/nodes/HumanticAI/GenericFunctions.ts index ac41db4ab7..68b82cb7a0 100644 --- a/packages/nodes-base/nodes/HumanticAI/GenericFunctions.ts +++ b/packages/nodes-base/nodes/HumanticAI/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function humanticAiApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { - const credentials = this.getCredentials('humanticAiApi'); + const credentials = await this.getCredentials('humanticAiApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Hunter/GenericFunctions.ts b/packages/nodes-base/nodes/Hunter/GenericFunctions.ts index a5385dd0b0..070b0f59e0 100644 --- a/packages/nodes-base/nodes/Hunter/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Hunter/GenericFunctions.ts @@ -8,7 +8,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function hunterApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('hunterApi'); + const credentials = await this.getCredentials('hunterApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Intercom/GenericFunctions.ts b/packages/nodes-base/nodes/Intercom/GenericFunctions.ts index 5f7602b56d..42ac234414 100644 --- a/packages/nodes-base/nodes/Intercom/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Intercom/GenericFunctions.ts @@ -12,7 +12,7 @@ import { } from 'n8n-workflow'; export async function intercomApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, endpoint: string, method: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('intercomApi'); + const credentials = await this.getCredentials('intercomApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts b/packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts index a43a86ecd1..4f8aacd522 100644 --- a/packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts +++ b/packages/nodes-base/nodes/InvoiceNinja/GenericFunctions.ts @@ -18,7 +18,7 @@ import { } from 'lodash'; export async function invoiceNinjaApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('invoiceNinjaApi'); + const credentials = await this.getCredentials('invoiceNinjaApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Iterable/GenericFunctions.ts b/packages/nodes-base/nodes/Iterable/GenericFunctions.ts index e4d21f8adf..688da08d8d 100644 --- a/packages/nodes-base/nodes/Iterable/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Iterable/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function iterableApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('iterableApi') as IDataObject; + const credentials = await this.getCredentials('iterableApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Jira/GenericFunctions.ts b/packages/nodes-base/nodes/Jira/GenericFunctions.ts index 8e384c1a76..4b87f32ed2 100644 --- a/packages/nodes-base/nodes/Jira/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Jira/GenericFunctions.ts @@ -23,9 +23,9 @@ export async function jiraSoftwareCloudApiRequest(this: IHookFunctions | IExecut let jiraCredentials: ICredentialDataDecryptedObject | undefined; if (jiraVersion === 'server') { - jiraCredentials = this.getCredentials('jiraSoftwareServerApi'); + jiraCredentials = await this.getCredentials('jiraSoftwareServerApi'); } else { - jiraCredentials = this.getCredentials('jiraSoftwareCloudApi'); + jiraCredentials = await this.getCredentials('jiraSoftwareCloudApi'); } if (jiraCredentials === undefined) { diff --git a/packages/nodes-base/nodes/JotForm/GenericFunctions.ts b/packages/nodes-base/nodes/JotForm/GenericFunctions.ts index 1f0bd6be97..0aff20da1e 100644 --- a/packages/nodes-base/nodes/JotForm/GenericFunctions.ts +++ b/packages/nodes-base/nodes/JotForm/GenericFunctions.ts @@ -9,7 +9,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function jotformApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('jotFormApi'); + const credentials = await this.getCredentials('jotFormApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Kafka/Kafka.node.ts b/packages/nodes-base/nodes/Kafka/Kafka.node.ts index 81dcabd21f..dea7de59ba 100644 --- a/packages/nodes-base/nodes/Kafka/Kafka.node.ts +++ b/packages/nodes-base/nodes/Kafka/Kafka.node.ts @@ -181,7 +181,7 @@ export class Kafka implements INodeType { compression = CompressionTypes.GZIP; } - const credentials = this.getCredentials('kafka') as IDataObject; + const credentials = await this.getCredentials('kafka') as IDataObject; const brokers = (credentials.brokers as string || '').split(',').map(item => item.trim()) as string[]; diff --git a/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts b/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts index d83538b3d9..ac194de43a 100644 --- a/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts +++ b/packages/nodes-base/nodes/Kafka/KafkaTrigger.node.ts @@ -116,7 +116,7 @@ export class KafkaTrigger implements INodeType { const groupId = this.getNodeParameter('groupId') as string; - const credentials = this.getCredentials('kafka') as IDataObject; + const credentials = await this.getCredentials('kafka') as IDataObject; const brokers = (credentials.brokers as string || '').split(',').map(item => item.trim()) as string[]; diff --git a/packages/nodes-base/nodes/Kitemaker/GenericFunctions.ts b/packages/nodes-base/nodes/Kitemaker/GenericFunctions.ts index 6b623a6a5f..80884f0e33 100644 --- a/packages/nodes-base/nodes/Kitemaker/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Kitemaker/GenericFunctions.ts @@ -13,7 +13,7 @@ export async function kitemakerRequest( this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, body: IDataObject = {}, ) { - const { personalAccessToken } = this.getCredentials('kitemakerApi') as { personalAccessToken: string }; + const { personalAccessToken } = await this.getCredentials('kitemakerApi') as { personalAccessToken: string }; const options = { headers: { diff --git a/packages/nodes-base/nodes/Lemlist/GenericFunctions.ts b/packages/nodes-base/nodes/Lemlist/GenericFunctions.ts index 2d325b6e54..e1577a9cd7 100644 --- a/packages/nodes-base/nodes/Lemlist/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Lemlist/GenericFunctions.ts @@ -25,7 +25,7 @@ export async function lemlistApiRequest( option: IDataObject = {}, ) { - const { apiKey } = this.getCredentials('lemlistApi') as { + const { apiKey } = await this.getCredentials('lemlistApi') as { apiKey: string, }; diff --git a/packages/nodes-base/nodes/LingvaNex/GenericFunctions.ts b/packages/nodes-base/nodes/LingvaNex/GenericFunctions.ts index 58a549edda..cf7341e4d5 100644 --- a/packages/nodes-base/nodes/LingvaNex/GenericFunctions.ts +++ b/packages/nodes-base/nodes/LingvaNex/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function lingvaNexApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { - const credentials = this.getCredentials('lingvaNexApi'); + const credentials = await this.getCredentials('lingvaNexApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/MQTT/Mqtt.node.ts b/packages/nodes-base/nodes/MQTT/Mqtt.node.ts index fc71fe6221..8b0cc76e4e 100644 --- a/packages/nodes-base/nodes/MQTT/Mqtt.node.ts +++ b/packages/nodes-base/nodes/MQTT/Mqtt.node.ts @@ -111,7 +111,7 @@ export class Mqtt implements INodeType { async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); const length = (items.length as unknown) as number; - const credentials = this.getCredentials('mqtt') as IDataObject; + const credentials = await this.getCredentials('mqtt') as IDataObject; const protocol = credentials.protocol as string || 'mqtt'; const host = credentials.host as string; diff --git a/packages/nodes-base/nodes/MQTT/MqttTrigger.node.ts b/packages/nodes-base/nodes/MQTT/MqttTrigger.node.ts index 94bbda8c18..a6a3056145 100644 --- a/packages/nodes-base/nodes/MQTT/MqttTrigger.node.ts +++ b/packages/nodes-base/nodes/MQTT/MqttTrigger.node.ts @@ -75,7 +75,7 @@ export class MqttTrigger implements INodeType { async trigger(this: ITriggerFunctions): Promise { - const credentials = this.getCredentials('mqtt'); + const credentials = await this.getCredentials('mqtt'); if (!credentials) { throw new NodeOperationError(this.getNode(), 'Credentials are mandatory!'); diff --git a/packages/nodes-base/nodes/Mailcheck/GenericFunctions.ts b/packages/nodes-base/nodes/Mailcheck/GenericFunctions.ts index ba9ef974e1..504a1d3606 100644 --- a/packages/nodes-base/nodes/Mailcheck/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mailcheck/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function mailCheckApiRequest(this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('mailcheckApi') as IDataObject; + const credentials = await this.getCredentials('mailcheckApi') as IDataObject; let options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Mailchimp/GenericFunctions.ts b/packages/nodes-base/nodes/Mailchimp/GenericFunctions.ts index 1ce5ae2338..d1df3eb360 100644 --- a/packages/nodes-base/nodes/Mailchimp/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mailchimp/GenericFunctions.ts @@ -35,7 +35,7 @@ export async function mailchimpApiRequest(this: IHookFunctions | IExecuteFunctio try { if (authenticationMethod === 'apiKey') { - const credentials = this.getCredentials('mailchimpApi'); + const credentials = await this.getCredentials('mailchimpApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -52,7 +52,7 @@ export async function mailchimpApiRequest(this: IHookFunctions | IExecuteFunctio return await this.helpers.request!(options); } else { - const credentials = this.getCredentials('mailchimpOAuth2Api') as IDataObject; + const credentials = await this.getCredentials('mailchimpOAuth2Api') as IDataObject; const { api_endpoint } = await getMetadata.call(this, credentials.oauthTokenData as IDataObject); @@ -95,8 +95,8 @@ export function validateJSON(json: string | undefined): any { // tslint:disable- return result; } -function getMetadata(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, oauthTokenData: IDataObject) { - const credentials = this.getCredentials('mailchimpOAuth2Api') as IDataObject; +async function getMetadata(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, oauthTokenData: IDataObject) { + const credentials = await this.getCredentials('mailchimpOAuth2Api') as IDataObject; const options: OptionsWithUrl = { headers: { 'Accept': 'application/json', diff --git a/packages/nodes-base/nodes/MailerLite/GenericFunctions.ts b/packages/nodes-base/nodes/MailerLite/GenericFunctions.ts index b1ad7a5248..2f98f8b949 100644 --- a/packages/nodes-base/nodes/MailerLite/GenericFunctions.ts +++ b/packages/nodes-base/nodes/MailerLite/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function mailerliteApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IHookFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('mailerLiteApi') as IDataObject; + const credentials = await this.getCredentials('mailerLiteApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Mailgun/Mailgun.node.ts b/packages/nodes-base/nodes/Mailgun/Mailgun.node.ts index 8bde27f8bb..fe9d338921 100644 --- a/packages/nodes-base/nodes/Mailgun/Mailgun.node.ts +++ b/packages/nodes-base/nodes/Mailgun/Mailgun.node.ts @@ -127,7 +127,7 @@ export class Mailgun implements INodeType { const html = this.getNodeParameter('html', itemIndex) as string; const attachmentPropertyString = this.getNodeParameter('attachments', itemIndex) as string; - const credentials = this.getCredentials('mailgunApi'); + const credentials = await this.getCredentials('mailgunApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Mailjet/GenericFunctions.ts b/packages/nodes-base/nodes/Mailjet/GenericFunctions.ts index fba2c896ce..72076b1b72 100644 --- a/packages/nodes-base/nodes/Mailjet/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mailjet/GenericFunctions.ts @@ -15,7 +15,7 @@ import { } from 'n8n-workflow'; export async function mailjetApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const emailApiCredentials = this.getCredentials('mailjetEmailApi'); + const emailApiCredentials = await this.getCredentials('mailjetEmailApi'); let options: OptionsWithUri = { headers: { Accept: 'application/json', @@ -35,7 +35,7 @@ export async function mailjetApiRequest(this: IExecuteFunctions | IExecuteSingle const base64Credentials = Buffer.from(`${emailApiCredentials.apiKey}:${emailApiCredentials.secretKey}`).toString('base64'); options.headers!['Authorization'] = `Basic ${base64Credentials}`; } else { - const smsApiCredentials = this.getCredentials('mailjetSmsApi'); + const smsApiCredentials = await this.getCredentials('mailjetSmsApi'); options.headers!['Authorization'] = `Bearer ${smsApiCredentials!.token}`; } try { diff --git a/packages/nodes-base/nodes/Mandrill/GenericFunctions.ts b/packages/nodes-base/nodes/Mandrill/GenericFunctions.ts index d7ae92907c..e4730f64c8 100644 --- a/packages/nodes-base/nodes/Mandrill/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mandrill/GenericFunctions.ts @@ -12,7 +12,7 @@ import * as _ from 'lodash'; import { NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function mandrillApiRequest(this: IExecuteFunctions | IHookFunctions | ILoadOptionsFunctions, resource: string, method: string, action: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('mandrillApi'); + const credentials = await this.getCredentials('mandrillApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Marketstack/GenericFunctions.ts b/packages/nodes-base/nodes/Marketstack/GenericFunctions.ts index 3a20c1ca26..76097aefb3 100644 --- a/packages/nodes-base/nodes/Marketstack/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Marketstack/GenericFunctions.ts @@ -19,7 +19,7 @@ export async function marketstackApiRequest( body: IDataObject = {}, qs: IDataObject = {}, ) { - const credentials = this.getCredentials('marketstackApi') as IDataObject; + const credentials = await this.getCredentials('marketstackApi') as IDataObject; const protocol = credentials.useHttps ? 'https' : 'http'; // Free API does not support HTTPS const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Matrix/GenericFunctions.ts b/packages/nodes-base/nodes/Matrix/GenericFunctions.ts index 70355430f2..1db691ab23 100644 --- a/packages/nodes-base/nodes/Matrix/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Matrix/GenericFunctions.ts @@ -50,7 +50,7 @@ export async function matrixApiRequest(this: IExecuteFunctions | IExecuteSingleF let response: any; // tslint:disable-line:no-any - const credentials = this.getCredentials('matrixApi'); + const credentials = await this.getCredentials('matrixApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Mattermost/GenericFunctions.ts b/packages/nodes-base/nodes/Mattermost/GenericFunctions.ts index eba84ade8e..a6bcacd8fe 100644 --- a/packages/nodes-base/nodes/Mattermost/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mattermost/GenericFunctions.ts @@ -31,7 +31,7 @@ export interface IAttachment { * @returns {Promise} */ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('mattermostApi'); + const credentials = await this.getCredentials('mattermostApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Mattermost/Mattermost.node.ts b/packages/nodes-base/nodes/Mattermost/Mattermost.node.ts index 50531502ae..1677c5be00 100644 --- a/packages/nodes-base/nodes/Mattermost/Mattermost.node.ts +++ b/packages/nodes-base/nodes/Mattermost/Mattermost.node.ts @@ -1940,7 +1940,7 @@ export class Mattermost implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - const credentials = this.getCredentials('mattermostApi'); + const credentials = await this.getCredentials('mattermostApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts index 0ec2d9b2cb..7dbe00ae1d 100644 --- a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts @@ -30,7 +30,7 @@ export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions let returnData; if (authenticationMethod === 'credentials') { - const credentials = this.getCredentials('mauticApi') as IDataObject; + const credentials = await this.getCredentials('mauticApi') as IDataObject; const base64Key = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64'); @@ -41,7 +41,7 @@ export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions //@ts-ignore returnData = await this.helpers.request(options); } else { - const credentials = this.getCredentials('mauticOAuth2Api') as IDataObject; + const credentials = await this.getCredentials('mauticOAuth2Api') as IDataObject; options.uri = `${credentials.url}${options.uri}`; //@ts-ignore diff --git a/packages/nodes-base/nodes/Medium/GenericFunctions.ts b/packages/nodes-base/nodes/Medium/GenericFunctions.ts index fe6b5358e2..c6d4daa06c 100644 --- a/packages/nodes-base/nodes/Medium/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Medium/GenericFunctions.ts @@ -32,7 +32,7 @@ export async function mediumApiRequest(this: IHookFunctions | IExecuteFunctions try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('mediumApi'); + const credentials = await this.getCredentials('mediumApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/MessageBird/GenericFunctions.ts b/packages/nodes-base/nodes/MessageBird/GenericFunctions.ts index 3501cc9275..95a9206bb1 100644 --- a/packages/nodes-base/nodes/MessageBird/GenericFunctions.ts +++ b/packages/nodes-base/nodes/MessageBird/GenericFunctions.ts @@ -27,7 +27,7 @@ export async function messageBirdApiRequest( body: IDataObject, query: IDataObject = {}, ): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('messageBirdApi'); + const credentials = await this.getCredentials('messageBirdApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials returned!'); } diff --git a/packages/nodes-base/nodes/Microsoft/Outlook/GenericFunctions.ts b/packages/nodes-base/nodes/Microsoft/Outlook/GenericFunctions.ts index 4486605212..243df33da1 100644 --- a/packages/nodes-base/nodes/Microsoft/Outlook/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Microsoft/Outlook/GenericFunctions.ts @@ -15,7 +15,7 @@ import { } from 'n8n-workflow'; export async function microsoftApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}, option: IDataObject = { json: true }): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('microsoftOutlookOAuth2Api'); + const credentials = await this.getCredentials('microsoftOutlookOAuth2Api'); let apiUrl = `https://graph.microsoft.com/v1.0/me${resource}`; // If accessing shared mailbox diff --git a/packages/nodes-base/nodes/Microsoft/Sql/MicrosoftSql.node.ts b/packages/nodes-base/nodes/Microsoft/Sql/MicrosoftSql.node.ts index 867928a24f..b387b8f9f0 100644 --- a/packages/nodes-base/nodes/Microsoft/Sql/MicrosoftSql.node.ts +++ b/packages/nodes-base/nodes/Microsoft/Sql/MicrosoftSql.node.ts @@ -214,7 +214,7 @@ export class MicrosoftSql implements INodeType { }; async execute(this: IExecuteFunctions): Promise { - const credentials = this.getCredentials('microsoftSql'); + const credentials = await this.getCredentials('microsoftSql'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Mindee/GenericFunctions.ts b/packages/nodes-base/nodes/Mindee/GenericFunctions.ts index 7c02343462..4d0d01f7d9 100644 --- a/packages/nodes-base/nodes/Mindee/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mindee/GenericFunctions.ts @@ -19,9 +19,9 @@ export async function mindeeApiRequest(this: IExecuteFunctions | IExecuteSingleF let credentials; if (resource === 'receipt') { - credentials = this.getCredentials('mindeeReceiptApi') as IDataObject; + credentials = await this.getCredentials('mindeeReceiptApi') as IDataObject; } else { - credentials = this.getCredentials('mindeeInvoiceApi') as IDataObject; + credentials = await this.getCredentials('mindeeInvoiceApi') as IDataObject; } const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Mocean/GenericFunctions.ts b/packages/nodes-base/nodes/Mocean/GenericFunctions.ts index e415afc0b8..3951df2dee 100644 --- a/packages/nodes-base/nodes/Mocean/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mocean/GenericFunctions.ts @@ -17,7 +17,7 @@ import { * @returns {Promise} */ export async function moceanApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('moceanApi'); + const credentials = await this.getCredentials('moceanApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/MondayCom/GenericFunctions.ts b/packages/nodes-base/nodes/MondayCom/GenericFunctions.ts index f835c856b3..70caedaf51 100644 --- a/packages/nodes-base/nodes/MondayCom/GenericFunctions.ts +++ b/packages/nodes-base/nodes/MondayCom/GenericFunctions.ts @@ -37,7 +37,7 @@ export async function mondayComApiRequest(this: IExecuteFunctions | IWebhookFunc options = Object.assign({}, options, option); try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('mondayComApi') as IDataObject; + const credentials = await this.getCredentials('mondayComApi') as IDataObject; options.headers = { Authorization: `Bearer ${credentials.apiToken}` }; diff --git a/packages/nodes-base/nodes/MongoDb/MongoDb.node.ts b/packages/nodes-base/nodes/MongoDb/MongoDb.node.ts index 2e83cf3be2..cd9fa97c69 100644 --- a/packages/nodes-base/nodes/MongoDb/MongoDb.node.ts +++ b/packages/nodes-base/nodes/MongoDb/MongoDb.node.ts @@ -31,7 +31,7 @@ export class MongoDb implements INodeType { async execute(this: IExecuteFunctions): Promise { const { database, connectionString } = validateAndResolveMongoCredentials( this, - this.getCredentials('mongoDb'), + await this.getCredentials('mongoDb'), ); const client: MongoClient = await MongoClient.connect(connectionString, { diff --git a/packages/nodes-base/nodes/MonicaCrm/GenericFunctions.ts b/packages/nodes-base/nodes/MonicaCrm/GenericFunctions.ts index 9adee57d2b..2d06b12d6c 100644 --- a/packages/nodes-base/nodes/MonicaCrm/GenericFunctions.ts +++ b/packages/nodes-base/nodes/MonicaCrm/GenericFunctions.ts @@ -25,7 +25,7 @@ export async function monicaCrmApiRequest( body: IDataObject = {}, qs: IDataObject = {}, ) { - const credentials = this.getCredentials('monicaCrmApi') as { apiToken: string, environment: string, domain: string }; + const credentials = await this.getCredentials('monicaCrmApi') as { apiToken: string, environment: string, domain: string }; if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Msg91/GenericFunctions.ts b/packages/nodes-base/nodes/Msg91/GenericFunctions.ts index a6d2e5a217..3abe1e39e0 100644 --- a/packages/nodes-base/nodes/Msg91/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Msg91/GenericFunctions.ts @@ -17,7 +17,7 @@ import { * @returns {Promise} */ export async function msg91ApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('msg91Api'); + const credentials = await this.getCredentials('msg91Api'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/MySql/MySql.node.ts b/packages/nodes-base/nodes/MySql/MySql.node.ts index 9c8f386de7..d6db615b63 100644 --- a/packages/nodes-base/nodes/MySql/MySql.node.ts +++ b/packages/nodes-base/nodes/MySql/MySql.node.ts @@ -213,7 +213,7 @@ export class MySql implements INodeType { async execute(this: IExecuteFunctions): Promise { - const credentials = this.getCredentials('mySql'); + const credentials = await this.getCredentials('mySql'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Nasa/GenericFunctions.ts b/packages/nodes-base/nodes/Nasa/GenericFunctions.ts index cc8764d1e1..8f4e4c0852 100644 --- a/packages/nodes-base/nodes/Nasa/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Nasa/GenericFunctions.ts @@ -13,7 +13,7 @@ import { export async function nasaApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, qs: IDataObject, option: IDataObject = {}, uri?: string | undefined): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('nasaApi') as IDataObject; + const credentials = await this.getCredentials('nasaApi') as IDataObject; qs.api_key = credentials['api_key'] as string; diff --git a/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts b/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts index f71b9ea0a0..ae96def71e 100644 --- a/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts +++ b/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts @@ -38,7 +38,7 @@ export async function nextCloudApiRequest(this: IHookFunctions | IExecuteFunctio try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('nextCloudApi'); + const credentials = await this.getCredentials('nextCloudApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } @@ -55,7 +55,7 @@ export async function nextCloudApiRequest(this: IHookFunctions | IExecuteFunctio } return await this.helpers.request(options); } else { - const credentials = this.getCredentials('nextCloudOAuth2Api'); + const credentials = await this.getCredentials('nextCloudOAuth2Api'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts index feb38b0d65..f27db51228 100644 --- a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts +++ b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts @@ -785,9 +785,9 @@ export class NextCloud implements INodeType { let credentials; if (authenticationMethod === 'accessToken') { - credentials = this.getCredentials('nextCloudApi'); + credentials = await this.getCredentials('nextCloudApi'); } else { - credentials = this.getCredentials('nextCloudOAuth2Api'); + credentials = await this.getCredentials('nextCloudOAuth2Api'); } if (credentials === undefined) { diff --git a/packages/nodes-base/nodes/NocoDB/GenericFunctions.ts b/packages/nodes-base/nodes/NocoDB/GenericFunctions.ts index abdb64c770..b47ea6fb84 100644 --- a/packages/nodes-base/nodes/NocoDB/GenericFunctions.ts +++ b/packages/nodes-base/nodes/NocoDB/GenericFunctions.ts @@ -35,7 +35,7 @@ interface IAttachment { * @returns {Promise} */ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: object, query?: IDataObject, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('nocoDb'); + const credentials = await this.getCredentials('nocoDb'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Notion/GenericFunctions.ts b/packages/nodes-base/nodes/Notion/GenericFunctions.ts index 862aaa1152..e6e4848967 100644 --- a/packages/nodes-base/nodes/Notion/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Notion/GenericFunctions.ts @@ -41,7 +41,7 @@ export async function notionApiRequest(this: IHookFunctions | IExecuteFunctions }; options = Object.assign({}, options, option); - const credentials = this.getCredentials('notionApi') as IDataObject; + const credentials = await this.getCredentials('notionApi') as IDataObject; options!.headers!['Authorization'] = `Bearer ${credentials.apiKey}`; return this.helpers.request!(options); diff --git a/packages/nodes-base/nodes/OpenWeatherMap.node.ts b/packages/nodes-base/nodes/OpenWeatherMap.node.ts index 70821ea19a..5c594fb5e4 100644 --- a/packages/nodes-base/nodes/OpenWeatherMap.node.ts +++ b/packages/nodes-base/nodes/OpenWeatherMap.node.ts @@ -208,7 +208,7 @@ export class OpenWeatherMap implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - const credentials = this.getCredentials('openWeatherMapApi'); + const credentials = await this.getCredentials('openWeatherMapApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Orbit/GenericFunctions.ts b/packages/nodes-base/nodes/Orbit/GenericFunctions.ts index f0d4713461..d98fece239 100644 --- a/packages/nodes-base/nodes/Orbit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Orbit/GenericFunctions.ts @@ -19,7 +19,7 @@ import { export async function orbitApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { - const credentials = this.getCredentials('orbitApi'); + const credentials = await this.getCredentials('orbitApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Oura/GenericFunctions.ts b/packages/nodes-base/nodes/Oura/GenericFunctions.ts index acf877b855..18a46a075b 100644 --- a/packages/nodes-base/nodes/Oura/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Oura/GenericFunctions.ts @@ -25,7 +25,7 @@ export async function ouraApiRequest( option: IDataObject = {}, ) { - const credentials = this.getCredentials('ouraApi'); + const credentials = await this.getCredentials('ouraApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Paddle/GenericFunctions.ts b/packages/nodes-base/nodes/Paddle/GenericFunctions.ts index b169582b5e..d24c66c2dc 100644 --- a/packages/nodes-base/nodes/Paddle/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Paddle/GenericFunctions.ts @@ -15,7 +15,7 @@ import { } from 'n8n-workflow'; export async function paddleApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, endpoint: string, method: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('paddleApi'); + const credentials = await this.getCredentials('paddleApi'); const productionUrl = 'https://vendors.paddle.com/api'; const sandboxUrl = 'https://sandbox-vendors.paddle.com/api'; diff --git a/packages/nodes-base/nodes/PagerDuty/GenericFunctions.ts b/packages/nodes-base/nodes/PagerDuty/GenericFunctions.ts index 8b514fbad7..23e3bb7238 100644 --- a/packages/nodes-base/nodes/PagerDuty/GenericFunctions.ts +++ b/packages/nodes-base/nodes/PagerDuty/GenericFunctions.ts @@ -48,7 +48,7 @@ export async function pagerDutyApiRequest(this: IExecuteFunctions | IWebhookFunc try { if (authenticationMethod === 'apiToken') { - const credentials = this.getCredentials('pagerDutyApi'); + const credentials = await this.getCredentials('pagerDutyApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/PayPal/GenericFunctions.ts b/packages/nodes-base/nodes/PayPal/GenericFunctions.ts index f3d0aa42b9..a7859b335c 100644 --- a/packages/nodes-base/nodes/PayPal/GenericFunctions.ts +++ b/packages/nodes-base/nodes/PayPal/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function payPalApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, endpoint: string, method: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('payPalApi'); + const credentials = await this.getCredentials('payPalApi'); const env = getEnvironment(credentials!.env as string); const tokenInfo = await getAccessToken.call(this); const headerWithAuthentication = Object.assign({ }, @@ -44,7 +44,7 @@ function getEnvironment(env: string): string { } async function getAccessToken(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('payPalApi'); + const credentials = await this.getCredentials('payPalApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts b/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts index 3ae4f2bdf9..c153522377 100644 --- a/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function peekalinkApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { - const credentials = this.getCredentials('peekalinkApi'); + const credentials = await this.getCredentials('peekalinkApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Phantombuster/GenericFunctions.ts b/packages/nodes-base/nodes/Phantombuster/GenericFunctions.ts index 3be209ea32..c044f85a30 100644 --- a/packages/nodes-base/nodes/Phantombuster/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Phantombuster/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function phantombusterApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('phantombusterApi') as IDataObject; + const credentials = await this.getCredentials('phantombusterApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts b/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts index 9df80ee928..b9efb550e3 100644 --- a/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Pipedrive/GenericFunctions.ts @@ -71,7 +71,7 @@ export async function pipedriveApiRequest(this: IHookFunctions | IExecuteFunctio try { if (authenticationMethod === 'basicAuth' || authenticationMethod === 'apiToken' || authenticationMethod === 'none') { - const credentials = this.getCredentials('pipedriveApi'); + const credentials = await this.getCredentials('pipedriveApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Pipedrive/PipedriveTrigger.node.ts b/packages/nodes-base/nodes/Pipedrive/PipedriveTrigger.node.ts index 067f41eb45..37a12b8576 100644 --- a/packages/nodes-base/nodes/Pipedrive/PipedriveTrigger.node.ts +++ b/packages/nodes-base/nodes/Pipedrive/PipedriveTrigger.node.ts @@ -268,7 +268,7 @@ export class PipedriveTrigger implements INodeType { }; if (incomingAuthentication === 'basicAuth') { - const httpBasicAuth = this.getCredentials('httpBasicAuth'); + const httpBasicAuth = await this.getCredentials('httpBasicAuth'); if (httpBasicAuth === undefined || !httpBasicAuth.user || !httpBasicAuth.password) { // Data is not defined on node so can not authenticate @@ -324,7 +324,7 @@ export class PipedriveTrigger implements INodeType { if (incomingAuthentication === 'basicAuth') { // Basic authorization is needed to call webhook - const httpBasicAuth = this.getCredentials('httpBasicAuth'); + const httpBasicAuth = await this.getCredentials('httpBasicAuth'); if (httpBasicAuth === undefined || !httpBasicAuth.user || !httpBasicAuth.password) { // Data is not defined on node so can not authenticate diff --git a/packages/nodes-base/nodes/Plivo/GenericFunctions.ts b/packages/nodes-base/nodes/Plivo/GenericFunctions.ts index 475b899c17..98ca7fa52f 100644 --- a/packages/nodes-base/nodes/Plivo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Plivo/GenericFunctions.ts @@ -26,7 +26,7 @@ export async function plivoApiRequest( qs: IDataObject = {}, ) { - const credentials = this.getCredentials('plivoApi') as { authId: string, authToken: string }; + const credentials = await this.getCredentials('plivoApi') as { authId: string, authToken: string }; if (!credentials) { throw new NodeOperationError(this.getNode(), 'No credentials returned!'); diff --git a/packages/nodes-base/nodes/PostHog/GenericFunctions.ts b/packages/nodes-base/nodes/PostHog/GenericFunctions.ts index 0b4cec52cc..11a03c992f 100644 --- a/packages/nodes-base/nodes/PostHog/GenericFunctions.ts +++ b/packages/nodes-base/nodes/PostHog/GenericFunctions.ts @@ -13,7 +13,7 @@ import { export async function posthogApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('postHogApi') as IDataObject; + const credentials = await this.getCredentials('postHogApi') as IDataObject; const base = credentials.url as string; diff --git a/packages/nodes-base/nodes/Postgres/Postgres.node.ts b/packages/nodes-base/nodes/Postgres/Postgres.node.ts index 2b7f49baab..8b38fb6128 100644 --- a/packages/nodes-base/nodes/Postgres/Postgres.node.ts +++ b/packages/nodes-base/nodes/Postgres/Postgres.node.ts @@ -253,7 +253,7 @@ export class Postgres implements INodeType { }; async execute(this: IExecuteFunctions): Promise { - const credentials = this.getCredentials('postgres'); + const credentials = await this.getCredentials('postgres'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Postmark/GenericFunctions.ts b/packages/nodes-base/nodes/Postmark/GenericFunctions.ts index 6caf415079..cf37eb28e1 100644 --- a/packages/nodes-base/nodes/Postmark/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Postmark/GenericFunctions.ts @@ -17,7 +17,7 @@ import { export async function postmarkApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method : string, endpoint : string, body: any = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('postmarkApi'); + const credentials = await this.getCredentials('postmarkApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/ProfitWell/GenericFunctions.ts b/packages/nodes-base/nodes/ProfitWell/GenericFunctions.ts index 5ad323fbc4..b286963ecc 100644 --- a/packages/nodes-base/nodes/ProfitWell/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ProfitWell/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function profitWellApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any try { - const credentials = this.getCredentials('profitWellApi'); + const credentials = await this.getCredentials('profitWellApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Pushcut/GenericFunctions.ts b/packages/nodes-base/nodes/Pushcut/GenericFunctions.ts index 3804132044..9c53ca6296 100644 --- a/packages/nodes-base/nodes/Pushcut/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Pushcut/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function pushcutApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, uri?: string | undefined, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('pushcutApi') as IDataObject; + const credentials = await this.getCredentials('pushcutApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Pushover/GenericFunctions.ts b/packages/nodes-base/nodes/Pushover/GenericFunctions.ts index 4fe876538c..a840ac9f1c 100644 --- a/packages/nodes-base/nodes/Pushover/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Pushover/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function pushoverApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('pushoverApi') as IDataObject; + const credentials = await this.getCredentials('pushoverApi') as IDataObject; if (method === 'GET') { qs.token = credentials.apiKey; diff --git a/packages/nodes-base/nodes/QuestDb/QuestDb.node.ts b/packages/nodes-base/nodes/QuestDb/QuestDb.node.ts index 50a4e7c9e4..2522be7231 100644 --- a/packages/nodes-base/nodes/QuestDb/QuestDb.node.ts +++ b/packages/nodes-base/nodes/QuestDb/QuestDb.node.ts @@ -210,7 +210,7 @@ export class QuestDb implements INodeType { }; async execute(this: IExecuteFunctions): Promise { - const credentials = this.getCredentials('questDb'); + const credentials = await this.getCredentials('questDb'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/QuickBase/GenericFunctions.ts b/packages/nodes-base/nodes/QuickBase/GenericFunctions.ts index d1393ddbfc..ec93b066b7 100644 --- a/packages/nodes-base/nodes/QuickBase/GenericFunctions.ts +++ b/packages/nodes-base/nodes/QuickBase/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function quickbaseApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('quickbaseApi') as IDataObject; + const credentials = await this.getCredentials('quickbaseApi') as IDataObject; if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/QuickBooks/GenericFunctions.ts b/packages/nodes-base/nodes/QuickBooks/GenericFunctions.ts index 35d3da16b6..72e3742939 100644 --- a/packages/nodes-base/nodes/QuickBooks/GenericFunctions.ts +++ b/packages/nodes-base/nodes/QuickBooks/GenericFunctions.ts @@ -61,7 +61,7 @@ export async function quickBooksApiRequest( const productionUrl = 'https://quickbooks.api.intuit.com'; const sandboxUrl = 'https://sandbox-quickbooks.api.intuit.com'; - const credentials = this.getCredentials('quickBooksOAuth2Api') as QuickBooksOAuth2Credentials; + const credentials = await this.getCredentials('quickBooksOAuth2Api') as QuickBooksOAuth2Credentials; const options: OptionsWithUri = { headers: { @@ -267,7 +267,7 @@ export async function loadResource( query: `SELECT * FROM ${resource}`, } as IDataObject; - const { oauthTokenData: { callbackQueryString: { realmId } } } = this.getCredentials('quickBooksOAuth2Api') as { oauthTokenData: { callbackQueryString: { realmId: string } } }; + const { oauthTokenData: { callbackQueryString: { realmId } } } = await this.getCredentials('quickBooksOAuth2Api') as { oauthTokenData: { callbackQueryString: { realmId: string } } }; const endpoint = `/v3/company/${realmId}/query`; const resourceItems = await quickBooksApiRequestAllItems.call(this, 'GET', endpoint, qs, {}, resource); diff --git a/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts b/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts index 2a9f254a5c..24df59f793 100644 --- a/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts +++ b/packages/nodes-base/nodes/QuickBooks/QuickBooks.node.ts @@ -200,8 +200,7 @@ export class QuickBooks implements INodeType { let responseData; const returnData: IDataObject[] = []; - const { oauthTokenData } = this.getCredentials('quickBooksOAuth2Api') as QuickBooksOAuth2Credentials; - + const { oauthTokenData } = await this.getCredentials('quickBooksOAuth2Api') as QuickBooksOAuth2Credentials; const companyId = oauthTokenData.callbackQueryString.realmId; for (let i = 0; i < items.length; i++) { diff --git a/packages/nodes-base/nodes/RabbitMQ/GenericFunctions.ts b/packages/nodes-base/nodes/RabbitMQ/GenericFunctions.ts index 2b3fc67833..22700746b7 100644 --- a/packages/nodes-base/nodes/RabbitMQ/GenericFunctions.ts +++ b/packages/nodes-base/nodes/RabbitMQ/GenericFunctions.ts @@ -7,7 +7,7 @@ import { const amqplib = require('amqplib'); export async function rabbitmqConnect(this: IExecuteFunctions | ITriggerFunctions, options: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('rabbitmq') as IDataObject; + const credentials = await this.getCredentials('rabbitmq') as IDataObject; const credentialKeys = [ 'hostname', diff --git a/packages/nodes-base/nodes/Redis/Redis.node.ts b/packages/nodes-base/nodes/Redis/Redis.node.ts index 3202fa576e..f7fd088aea 100644 --- a/packages/nodes-base/nodes/Redis/Redis.node.ts +++ b/packages/nodes-base/nodes/Redis/Redis.node.ts @@ -480,12 +480,12 @@ export class Redis implements INodeType { }; - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { // TODO: For array and object fields it should not have a "value" field it should // have a parameter field for a path. Because it is not possible to set // array, object via parameter directly (should maybe be possible?!?!) // Should maybe have a parameter which is JSON. - const credentials = this.getCredentials('redis'); + const credentials = await this.getCredentials('redis'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts index 5ed00d3601..3453675579 100644 --- a/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Rocketchat/GenericFunctions.ts @@ -10,7 +10,7 @@ import { import { NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function rocketchatApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, resource: string, method: string, operation: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('rocketchatApi'); + const credentials = await this.getCredentials('rocketchatApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/S3/GenericFunctions.ts b/packages/nodes-base/nodes/S3/GenericFunctions.ts index 1e53f85073..40d2cc2719 100644 --- a/packages/nodes-base/nodes/S3/GenericFunctions.ts +++ b/packages/nodes-base/nodes/S3/GenericFunctions.ts @@ -31,7 +31,7 @@ export async function s3ApiRequest(this: IHookFunctions | IExecuteFunctions | IL let credentials; - credentials = this.getCredentials('s3'); + credentials = await this.getCredentials('s3'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/S3/S3.node.ts b/packages/nodes-base/nodes/S3/S3.node.ts index f9cdb0e2a8..c1c53096c1 100644 --- a/packages/nodes-base/nodes/S3/S3.node.ts +++ b/packages/nodes-base/nodes/S3/S3.node.ts @@ -119,7 +119,7 @@ export class S3 implements INodeType { let credentials; try { - credentials = this.getCredentials('s3'); + credentials = await this.getCredentials('s3'); } catch (error) { throw new NodeApiError(this.getNode(), error); } diff --git a/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts b/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts index 1671e54c94..11f26e66e0 100644 --- a/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Salesforce/GenericFunctions.ts @@ -28,7 +28,7 @@ export async function salesforceApiRequest(this: IExecuteFunctions | IExecuteSin if (authenticationMethod === 'jwt') { // https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm&type=5 const credentialsType = 'salesforceJwtApi'; - const credentials = this.getCredentials(credentialsType); + const credentials = await this.getCredentials(credentialsType); const response = await getAccessToken.call(this, credentials as IDataObject); const { instance_url, access_token } = response; const options = getOptions.call(this, method, (uri || endpoint), body, qs, instance_url as string); @@ -40,7 +40,7 @@ export async function salesforceApiRequest(this: IExecuteFunctions | IExecuteSin } else { // https://help.salesforce.com/articleView?id=remoteaccess_oauth_web_server_flow.htm&type=5 const credentialsType = 'salesforceOAuth2Api'; - const credentials = this.getCredentials(credentialsType) as { oauthTokenData: { instance_url: string } }; + const credentials = await this.getCredentials(credentialsType) as { oauthTokenData: { instance_url: string } }; const options = getOptions.call(this, method, (uri || endpoint), body, qs, credentials.oauthTokenData.instance_url); Logger.debug(`Authentication for "Salesforce" node is using "OAuth2". Invoking URI ${options.uri}`); Object.assign(options, option); diff --git a/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts b/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts index f0a7694a85..9a419e3b82 100644 --- a/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Salesmate/GenericFunctions.ts @@ -9,7 +9,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function salesmateApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('salesmateApi'); + const credentials = await this.getCredentials('salesmateApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/SecurityScorecard/GenericFunctions.ts b/packages/nodes-base/nodes/SecurityScorecard/GenericFunctions.ts index c2255961fd..319d774b99 100644 --- a/packages/nodes-base/nodes/SecurityScorecard/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SecurityScorecard/GenericFunctions.ts @@ -13,7 +13,7 @@ import { } from 'n8n-workflow'; export async function scorecardApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('securityScorecardApi'); + const credentials = await this.getCredentials('securityScorecardApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Segment/GenericFunctions.ts b/packages/nodes-base/nodes/Segment/GenericFunctions.ts index bb539d7966..e692e1d4a2 100644 --- a/packages/nodes-base/nodes/Segment/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Segment/GenericFunctions.ts @@ -9,7 +9,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function segmentApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('segmentApi'); + const credentials = await this.getCredentials('segmentApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/SendGrid/GenericFunctions.ts b/packages/nodes-base/nodes/SendGrid/GenericFunctions.ts index fe44dbf90f..4615f95b50 100644 --- a/packages/nodes-base/nodes/SendGrid/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SendGrid/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function sendGridApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, endpoint: string, method: string, body: any = {}, qs: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('sendGridApi') as IDataObject; + const credentials = await this.getCredentials('sendGridApi') as IDataObject; const host = 'api.sendgrid.com/v3'; diff --git a/packages/nodes-base/nodes/Sendy/GenericFunctions.ts b/packages/nodes-base/nodes/Sendy/GenericFunctions.ts index 4df80113e3..0c58e3d59e 100644 --- a/packages/nodes-base/nodes/Sendy/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Sendy/GenericFunctions.ts @@ -13,7 +13,7 @@ import { export async function sendyApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('sendyApi') as IDataObject; + const credentials = await this.getCredentials('sendyApi') as IDataObject; body.api_key = credentials.apiKey; diff --git a/packages/nodes-base/nodes/SentryIo/GenericFunctions.ts b/packages/nodes-base/nodes/SentryIo/GenericFunctions.ts index caa5e7bb6f..667593e70e 100644 --- a/packages/nodes-base/nodes/SentryIo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SentryIo/GenericFunctions.ts @@ -50,7 +50,7 @@ export async function sentryIoApiRequest(this: IHookFunctions | IExecuteFunction credentialName = 'sentryIoServerApi'; } - const credentials = this.getCredentials(credentialName); + const credentials = await this.getCredentials(credentialName); if (credentials?.url) { options.uri = `${credentials?.url}${resource}`; diff --git a/packages/nodes-base/nodes/ServiceNow/GenericFunctions.ts b/packages/nodes-base/nodes/ServiceNow/GenericFunctions.ts index 4b069a4929..2924cdf53d 100644 --- a/packages/nodes-base/nodes/ServiceNow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ServiceNow/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function serviceNowApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('serviceNowOAuth2Api'); + const credentials = await this.getCredentials('serviceNowOAuth2Api'); const options: OptionsWithUri = { headers: {}, diff --git a/packages/nodes-base/nodes/Shopify/GenericFunctions.ts b/packages/nodes-base/nodes/Shopify/GenericFunctions.ts index 51c3fc543e..ca728e4213 100644 --- a/packages/nodes-base/nodes/Shopify/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Shopify/GenericFunctions.ts @@ -19,7 +19,7 @@ import { } from 'change-case'; export async function shopifyApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('shopifyApi'); + const credentials = await this.getCredentials('shopifyApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Shopify/ShopifyTrigger.node.ts b/packages/nodes-base/nodes/Shopify/ShopifyTrigger.node.ts index fe999a8f9a..1a433171bd 100644 --- a/packages/nodes-base/nodes/Shopify/ShopifyTrigger.node.ts +++ b/packages/nodes-base/nodes/Shopify/ShopifyTrigger.node.ts @@ -358,7 +358,7 @@ export class ShopifyTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { const headerData = this.getHeaderData() as IDataObject; const req = this.getRequestObject(); - const credentials = this.getCredentials('shopifyApi') as IDataObject; + const credentials = await this.getCredentials('shopifyApi') as IDataObject; const topic = this.getNodeParameter('topic') as string; if (headerData['x-shopify-topic'] !== undefined && headerData['x-shopify-hmac-sha256'] !== undefined diff --git a/packages/nodes-base/nodes/Signl4/GenericFunctions.ts b/packages/nodes-base/nodes/Signl4/GenericFunctions.ts index 0095542ab8..3254932ef5 100644 --- a/packages/nodes-base/nodes/Signl4/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Signl4/GenericFunctions.ts @@ -25,7 +25,7 @@ import { */ export async function SIGNL4ApiRequest(this: IExecuteFunctions, method: string, body: string, query: IDataObject = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('signl4Api'); + const credentials = await this.getCredentials('signl4Api'); const teamSecret = credentials?.teamSecret as string; diff --git a/packages/nodes-base/nodes/Slack/GenericFunctions.ts b/packages/nodes-base/nodes/Slack/GenericFunctions.ts index 70fbf195fd..033c87dfef 100644 --- a/packages/nodes-base/nodes/Slack/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Slack/GenericFunctions.ts @@ -40,7 +40,7 @@ export async function slackApiRequest(this: IExecuteFunctions | IExecuteSingleFu let response: any; // tslint:disable-line:no-any if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('slackApi'); + const credentials = await this.getCredentials('slackApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Sms77/GenericFunctions.ts b/packages/nodes-base/nodes/Sms77/GenericFunctions.ts index aa104b6297..78dcb81184 100644 --- a/packages/nodes-base/nodes/Sms77/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Sms77/GenericFunctions.ts @@ -21,7 +21,7 @@ import { * @returns {Promise} */ export async function sms77ApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, form: IDataObject, qs?: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('sms77Api'); + const credentials = await this.getCredentials('sms77Api'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Snowflake/Snowflake.node.ts b/packages/nodes-base/nodes/Snowflake/Snowflake.node.ts index 4da65da65a..8be88202fb 100644 --- a/packages/nodes-base/nodes/Snowflake/Snowflake.node.ts +++ b/packages/nodes-base/nodes/Snowflake/Snowflake.node.ts @@ -176,7 +176,7 @@ export class Snowflake implements INodeType { }; async execute(this: IExecuteFunctions): Promise { - const credentials = this.getCredentials('snowflake') as unknown as snowflake.ConnectionOptions; + const credentials = await this.getCredentials('snowflake') as unknown as snowflake.ConnectionOptions; const returnData: IDataObject[] = []; let responseData; diff --git a/packages/nodes-base/nodes/Spontit/GenericFunctions.ts b/packages/nodes-base/nodes/Spontit/GenericFunctions.ts index 706b10d372..9697c79544 100644 --- a/packages/nodes-base/nodes/Spontit/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Spontit/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function spontitApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('spontitApi') as IDataObject; + const credentials = await this.getCredentials('spontitApi') as IDataObject; try { const options: OptionsWithUri = { diff --git a/packages/nodes-base/nodes/Ssh/Ssh.node.ts b/packages/nodes-base/nodes/Ssh/Ssh.node.ts index b136752527..e9d1232435 100644 --- a/packages/nodes-base/nodes/Ssh/Ssh.node.ts +++ b/packages/nodes-base/nodes/Ssh/Ssh.node.ts @@ -295,7 +295,7 @@ export class Ssh implements INodeType { try { if (authentication === 'password') { - const credentials = this.getCredentials('sshPassword') as IDataObject; + const credentials = await this.getCredentials('sshPassword') as IDataObject; await ssh.connect({ host: credentials.host as string, @@ -306,7 +306,7 @@ export class Ssh implements INodeType { } else if (authentication === 'privateKey') { - const credentials = this.getCredentials('sshPrivateKey') as IDataObject; + const credentials = await this.getCredentials('sshPrivateKey') as IDataObject; const { path, } = await file({ prefix: 'n8n-ssh-' }); temporaryFiles.push(path); diff --git a/packages/nodes-base/nodes/Stackby/GenericFunction.ts b/packages/nodes-base/nodes/Stackby/GenericFunction.ts index a39cb9be12..53ffaca132 100644 --- a/packages/nodes-base/nodes/Stackby/GenericFunction.ts +++ b/packages/nodes-base/nodes/Stackby/GenericFunction.ts @@ -24,7 +24,7 @@ import { * @returns {Promise} */ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('stackbyApi') as IDataObject; + const credentials = await this.getCredentials('stackbyApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Storyblok/GenericFunctions.ts b/packages/nodes-base/nodes/Storyblok/GenericFunctions.ts index 7ed4e462da..74c4946495 100644 --- a/packages/nodes-base/nodes/Storyblok/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Storyblok/GenericFunctions.ts @@ -34,13 +34,13 @@ export async function storyblokApiRequest(this: IHookFunctions | IExecuteFunctio } if (authenticationMethod === 'contentApi') { - const credentials = this.getCredentials('storyblokContentApi') as IDataObject; + const credentials = await this.getCredentials('storyblokContentApi') as IDataObject; options.uri = `https://api.storyblok.com${resource}`; Object.assign(options.qs, { token: credentials.apiKey }); } else { - const credentials = this.getCredentials('storyblokManagementApi') as IDataObject; + const credentials = await this.getCredentials('storyblokManagementApi') as IDataObject; options.uri = `https://mapi.storyblok.com${resource}`; diff --git a/packages/nodes-base/nodes/Strapi/GenericFunctions.ts b/packages/nodes-base/nodes/Strapi/GenericFunctions.ts index 1164d6b021..e8112b05ce 100644 --- a/packages/nodes-base/nodes/Strapi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Strapi/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function strapiApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('strapiApi') as IDataObject; + const credentials = await this.getCredentials('strapiApi') as IDataObject; try { const options: OptionsWithUri = { @@ -41,7 +41,7 @@ export async function strapiApiRequest(this: IExecuteFunctions | ILoadOptionsFun } export async function getToken(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('strapiApi') as IDataObject; + const credentials = await this.getCredentials('strapiApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Strava/GenericFunctions.ts b/packages/nodes-base/nodes/Strava/GenericFunctions.ts index f854b7ad3d..531fbcf4da 100644 --- a/packages/nodes-base/nodes/Strava/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Strava/GenericFunctions.ts @@ -32,7 +32,7 @@ export async function stravaApiRequest(this: IExecuteFunctions | IExecuteSingleF } if (this.getNode().type.includes('Trigger') && resource.includes('/push_subscriptions')) { - const credentials = this.getCredentials('stravaOAuth2Api') as IDataObject; + const credentials = await this.getCredentials('stravaOAuth2Api') as IDataObject; if (method === 'GET') { qs.client_id = credentials.clientId; qs.client_secret = credentials.clientSecret; diff --git a/packages/nodes-base/nodes/Stripe/helpers.ts b/packages/nodes-base/nodes/Stripe/helpers.ts index c4d5e06c65..c7ec812a4a 100644 --- a/packages/nodes-base/nodes/Stripe/helpers.ts +++ b/packages/nodes-base/nodes/Stripe/helpers.ts @@ -36,7 +36,7 @@ export async function stripeApiRequest( body: object, query?: object, ) { - const credentials = this.getCredentials('stripeApi'); + const credentials = await this.getCredentials('stripeApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/SurveyMonkey/GenericFunctions.ts b/packages/nodes-base/nodes/SurveyMonkey/GenericFunctions.ts index d09ba54b4c..292fc3c74b 100644 --- a/packages/nodes-base/nodes/SurveyMonkey/GenericFunctions.ts +++ b/packages/nodes-base/nodes/SurveyMonkey/GenericFunctions.ts @@ -41,7 +41,7 @@ export async function surveyMonkeyApiRequest(this: IExecuteFunctions | IWebhookF try { if ( authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('surveyMonkeyApi'); + const credentials = await this.getCredentials('surveyMonkeyApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.ts b/packages/nodes-base/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.ts index e285003f6e..88bc851632 100644 --- a/packages/nodes-base/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.ts +++ b/packages/nodes-base/nodes/SurveyMonkey/SurveyMonkeyTrigger.node.ts @@ -497,9 +497,9 @@ export class SurveyMonkeyTrigger implements INodeType { const webhookName = this.getWebhookName(); if (authenticationMethod === 'accessToken') { - credentials = this.getCredentials('surveyMonkeyApi') as IDataObject; + credentials = await this.getCredentials('surveyMonkeyApi') as IDataObject; } else { - credentials = this.getCredentials('surveyMonkeyOAuth2Api') as IDataObject; + credentials = await this.getCredentials('surveyMonkeyOAuth2Api') as IDataObject; } if (webhookName === 'setup') { diff --git a/packages/nodes-base/nodes/Taiga/GenericFunctions.ts b/packages/nodes-base/nodes/Taiga/GenericFunctions.ts index d6c8a4a10c..9bf79988f7 100644 --- a/packages/nodes-base/nodes/Taiga/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Taiga/GenericFunctions.ts @@ -60,7 +60,7 @@ export async function taigaApiRequest( uri?: string | undefined, option = {}, ): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('taigaApi') as ICredentialDataDecryptedObject; + const credentials = await this.getCredentials('taigaApi') as ICredentialDataDecryptedObject; const authToken = await getAuthorization.call(this, credentials); diff --git a/packages/nodes-base/nodes/Taiga/TaigaTrigger.node.ts b/packages/nodes-base/nodes/Taiga/TaigaTrigger.node.ts index 0a63f51ae4..5ee2358744 100644 --- a/packages/nodes-base/nodes/Taiga/TaigaTrigger.node.ts +++ b/packages/nodes-base/nodes/Taiga/TaigaTrigger.node.ts @@ -176,7 +176,7 @@ export class TaigaTrigger implements INodeType { return false; }, async create(this: IHookFunctions): Promise { - const credentials = this.getCredentials('taigaApi') as ICredentialDataDecryptedObject; + const credentials = await this.getCredentials('taigaApi') as ICredentialDataDecryptedObject; const webhookUrl = this.getNodeWebhookUrl('default') as string; diff --git a/packages/nodes-base/nodes/Tapfiliate/GenericFunctions.ts b/packages/nodes-base/nodes/Tapfiliate/GenericFunctions.ts index bcceb04d86..7114b3052c 100644 --- a/packages/nodes-base/nodes/Tapfiliate/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Tapfiliate/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function tapfiliateApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, qs: IDataObject = {}, uri?: string | undefined, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('tapfiliateApi') as IDataObject; + const credentials = await this.getCredentials('tapfiliateApi') as IDataObject; const options: OptionsWithUri = { headers: { diff --git a/packages/nodes-base/nodes/Telegram/GenericFunctions.ts b/packages/nodes-base/nodes/Telegram/GenericFunctions.ts index b5df173bf1..f3b6005677 100644 --- a/packages/nodes-base/nodes/Telegram/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Telegram/GenericFunctions.ts @@ -143,7 +143,7 @@ export function addAdditionalFields(this: IExecuteFunctions, body: IDataObject, * @returns {Promise} */ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, endpoint: string, body: object, query?: IDataObject, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('telegramApi'); + const credentials = await this.getCredentials('telegramApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Telegram/Telegram.node.ts b/packages/nodes-base/nodes/Telegram/Telegram.node.ts index e386aea911..43c0873655 100644 --- a/packages/nodes-base/nodes/Telegram/Telegram.node.ts +++ b/packages/nodes-base/nodes/Telegram/Telegram.node.ts @@ -2062,7 +2062,7 @@ export class Telegram implements INodeType { if (this.getNodeParameter('download', i, false) as boolean === true) { const filePath = responseData.result.file_path; - const credentials = this.getCredentials('telegramApi'); + const credentials = await this.getCredentials('telegramApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts b/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts index 554983cef9..91e00a4022 100644 --- a/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts +++ b/packages/nodes-base/nodes/Telegram/TelegramTrigger.node.ts @@ -210,7 +210,7 @@ export class TelegramTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { - const credentials = this.getCredentials('telegramApi') as IDataObject; + const credentials = await this.getCredentials('telegramApi') as IDataObject; const bodyData = this.getBodyData() as IEvent; diff --git a/packages/nodes-base/nodes/TheHive/GenericFunctions.ts b/packages/nodes-base/nodes/TheHive/GenericFunctions.ts index d37cf9f770..ff2556e6f5 100644 --- a/packages/nodes-base/nodes/TheHive/GenericFunctions.ts +++ b/packages/nodes-base/nodes/TheHive/GenericFunctions.ts @@ -16,7 +16,7 @@ import * as moment from 'moment'; import { Eq } from './QueryFunctions'; export async function theHiveApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('theHiveApi'); + const credentials = await this.getCredentials('theHiveApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -112,7 +112,11 @@ export async function prepareCustomFields(this: IHookFunctions | IExecuteFunctio } } else if (additionalFields.customFieldsUi) { // Get Custom Field Types from TheHive - const version = this.getCredentials('theHiveApi')?.apiVersion; + const credentials = await this.getCredentials('theHiveApi'); + if (credentials === undefined) { + throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); + } + const version = credentials.apiVersion; const endpoint = version === 'v1' ? '/customField' : '/list/custom_fields'; const requestResult = await theHiveApiRequest.call( diff --git a/packages/nodes-base/nodes/TheHive/TheHive.node.ts b/packages/nodes-base/nodes/TheHive/TheHive.node.ts index 62894dae66..037e02fbb4 100644 --- a/packages/nodes-base/nodes/TheHive/TheHive.node.ts +++ b/packages/nodes-base/nodes/TheHive/TheHive.node.ts @@ -182,7 +182,11 @@ export class TheHive implements INodeType { return returnData; }, async loadCustomFields(this: ILoadOptionsFunctions): Promise { - const version = this.getCredentials('theHiveApi')?.apiVersion; + const credentials = await this.getCredentials('theHiveApi'); + if (credentials === undefined) { + throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); + } + const version = credentials.apiVersion; const endpoint = version === 'v1' ? '/customField' : '/list/custom_fields'; const requestResult = await theHiveApiRequest.call( @@ -208,7 +212,7 @@ export class TheHive implements INodeType { }, async loadObservableOptions(this: ILoadOptionsFunctions): Promise { // if v1 is not used we remove 'count' option - const version = this.getCredentials('theHiveApi')?.apiVersion; + const version = (await this.getCredentials('theHiveApi'))?.apiVersion; const options = [ ...(version === 'v1') ? [{ name: 'Count', value: 'count', description: 'Count observables' }] : [], @@ -223,7 +227,7 @@ export class TheHive implements INodeType { return options; }, async loadObservableTypes(this: ILoadOptionsFunctions): Promise { - const version = this.getCredentials('theHiveApi')?.apiVersion; + const version = (await this.getCredentials('theHiveApi'))?.apiVersion; const endpoint = version === 'v1' ? '/observable/type?range=all' : '/list/list_artifactDataType'; const dataTypes = await theHiveApiRequest.call( @@ -267,7 +271,11 @@ export class TheHive implements INodeType { return returnData; }, async loadTaskOptions(this: ILoadOptionsFunctions): Promise { - const version = this.getCredentials('theHiveApi')?.apiVersion; + const credentials = await this.getCredentials('theHiveApi'); + if (credentials === undefined) { + throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); + } + const version = credentials.apiVersion; const options = [ ...(version === 'v1') ? [{ name: 'Count', value: 'count', description: 'Count tasks' }] : [], { name: 'Create', value: 'create', description: 'Create a task' }, @@ -280,7 +288,11 @@ export class TheHive implements INodeType { return options; }, async loadAlertOptions(this: ILoadOptionsFunctions): Promise { - const version = this.getCredentials('theHiveApi')?.apiVersion; + const credentials = await this.getCredentials('theHiveApi'); + if (credentials === undefined) { + throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); + } + const version = credentials.apiVersion; const options = [ ...(version === 'v1') ? [{ name: 'Count', value: 'count', description: 'Count alerts' }] : [], { name: 'Create', value: 'create', description: 'Create alert' }, @@ -296,7 +308,11 @@ export class TheHive implements INodeType { return options; }, async loadCaseOptions(this: ILoadOptionsFunctions): Promise { - const version = this.getCredentials('theHiveApi')?.apiVersion; + const credentials = await this.getCredentials('theHiveApi'); + if (credentials === undefined) { + throw new NodeOperationError(this.getNode(), 'Credentials could not be obtained'); + } + const version = credentials.apiVersion; const options = [ ...(version === 'v1') ? [{ name: 'Count', value: 'count', description: 'Count a case' }] : [], { name: 'Create', value: 'create', description: 'Create a case' }, @@ -528,9 +544,8 @@ export class TheHive implements INodeType { {}, ); } - if (operation === 'getAll') { - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -961,7 +976,7 @@ export class TheHive implements INodeType { if (operation === 'get') { const observableId = this.getNodeParameter('id', i) as string; - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const version = credentials.apiVersion; @@ -1006,7 +1021,7 @@ export class TheHive implements INodeType { } if (operation === 'getAll') { - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1079,7 +1094,7 @@ export class TheHive implements INodeType { } if (operation === 'search') { - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1343,7 +1358,7 @@ export class TheHive implements INodeType { if (operation === 'get') { const caseId = this.getNodeParameter('id', i) as string; - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const version = credentials.apiVersion; @@ -1388,7 +1403,7 @@ export class TheHive implements INodeType { } if (operation === 'getAll') { - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1632,7 +1647,7 @@ export class TheHive implements INodeType { if (operation === 'get') { const taskId = this.getNodeParameter('id', i) as string; - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const version = credentials.apiVersion; @@ -1676,7 +1691,7 @@ export class TheHive implements INodeType { if (operation === 'getAll') { // get all require a case id (it retursn all tasks for a specific case) - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1751,7 +1766,7 @@ export class TheHive implements INodeType { } if (operation === 'search') { - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; @@ -1974,7 +1989,7 @@ export class TheHive implements INodeType { if (operation === 'get') { const logId = this.getNodeParameter('id', i) as string; - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const version = credentials.apiVersion; @@ -2018,7 +2033,7 @@ export class TheHive implements INodeType { } if (operation === 'getAll') { - const credentials = this.getCredentials('theHiveApi') as IDataObject; + const credentials = await this.getCredentials('theHiveApi') as IDataObject; const returnAll = this.getNodeParameter('returnAll', i) as boolean; diff --git a/packages/nodes-base/nodes/TimescaleDb/TimescaleDb.node.ts b/packages/nodes-base/nodes/TimescaleDb/TimescaleDb.node.ts index 32e7590d47..693c57b302 100644 --- a/packages/nodes-base/nodes/TimescaleDb/TimescaleDb.node.ts +++ b/packages/nodes-base/nodes/TimescaleDb/TimescaleDb.node.ts @@ -274,7 +274,7 @@ export class TimescaleDb implements INodeType { }; async execute(this: IExecuteFunctions): Promise { - const credentials = this.getCredentials('timescaleDb'); + const credentials = await this.getCredentials('timescaleDb'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Todoist/GenericFunctions.ts b/packages/nodes-base/nodes/Todoist/GenericFunctions.ts index a6f12e148d..97665c3c4c 100644 --- a/packages/nodes-base/nodes/Todoist/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Todoist/GenericFunctions.ts @@ -40,7 +40,7 @@ export async function todoistApiRequest( try { if (authentication === 'apiKey') { - const credentials = this.getCredentials('todoistApi') as IDataObject; + const credentials = await this.getCredentials('todoistApi') as IDataObject; //@ts-ignore options.headers['Authorization'] = `Bearer ${credentials.apiKey}`; diff --git a/packages/nodes-base/nodes/Toggl/GenericFunctions.ts b/packages/nodes-base/nodes/Toggl/GenericFunctions.ts index 8c4fd11306..c694cf6008 100644 --- a/packages/nodes-base/nodes/Toggl/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Toggl/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function togglApiRequest(this: ITriggerFunctions | IPollFunctions | IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('togglApi'); + const credentials = await this.getCredentials('togglApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/TravisCi/GenericFunctions.ts b/packages/nodes-base/nodes/TravisCi/GenericFunctions.ts index 2451eb9ed6..2d167150e8 100644 --- a/packages/nodes-base/nodes/TravisCi/GenericFunctions.ts +++ b/packages/nodes-base/nodes/TravisCi/GenericFunctions.ts @@ -20,7 +20,7 @@ import { import * as querystring from 'querystring'; export async function travisciApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('travisCiApi'); + const credentials = await this.getCredentials('travisCiApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Trello/GenericFunctions.ts b/packages/nodes-base/nodes/Trello/GenericFunctions.ts index a90d1e88f1..df29f882d8 100644 --- a/packages/nodes-base/nodes/Trello/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Trello/GenericFunctions.ts @@ -22,7 +22,7 @@ import { * @returns {Promise} */ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('trelloApi'); + const credentials = await this.getCredentials('trelloApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts b/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts index 0ed7aa2e86..57ecc95ef4 100644 --- a/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts +++ b/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts @@ -69,7 +69,7 @@ export class TrelloTrigger implements INodeType { webhookMethods = { default: { async checkExists(this: IHookFunctions): Promise { - const credentials = this.getCredentials('trelloApi'); + const credentials = await this.getCredentials('trelloApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -98,7 +98,7 @@ export class TrelloTrigger implements INodeType { async create(this: IHookFunctions): Promise { const webhookUrl = this.getNodeWebhookUrl('default'); - const credentials = this.getCredentials('trelloApi'); + const credentials = await this.getCredentials('trelloApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } @@ -129,7 +129,7 @@ export class TrelloTrigger implements INodeType { const webhookData = this.getWorkflowStaticData('node'); if (webhookData.webhookId !== undefined) { - const credentials = this.getCredentials('trelloApi'); + const credentials = await this.getCredentials('trelloApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } @@ -170,7 +170,7 @@ export class TrelloTrigger implements INodeType { const bodyData = this.getBodyData(); - const credentials = this.getCredentials('trelloApi'); + const credentials = await this.getCredentials('trelloApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Twake/GenericFunctions.ts b/packages/nodes-base/nodes/Twake/GenericFunctions.ts index 141d7493e4..dd4360702c 100644 --- a/packages/nodes-base/nodes/Twake/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Twake/GenericFunctions.ts @@ -34,11 +34,11 @@ export async function twakeApiRequest(this: IHookFunctions | IExecuteFunctions | // if (authenticationMethod === 'cloud') { - const credentials = this.getCredentials('twakeCloudApi'); + const credentials = await this.getCredentials('twakeCloudApi'); options.headers!.Authorization = `Bearer ${credentials!.workspaceKey}`; // } else { - // const credentials = this.getCredentials('twakeServerApi'); + // const credentials = await this.getCredentials('twakeServerApi'); // options.auth = { user: credentials!.publicId as string, pass: credentials!.privateApiKey as string }; // options.uri = `${credentials!.hostUrl}/api/v1${resource}`; // } diff --git a/packages/nodes-base/nodes/Twilio/GenericFunctions.ts b/packages/nodes-base/nodes/Twilio/GenericFunctions.ts index 3532030f3c..086e930064 100644 --- a/packages/nodes-base/nodes/Twilio/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Twilio/GenericFunctions.ts @@ -21,7 +21,7 @@ import { * @returns {Promise} */ export async function twilioApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('twilioApi') as { + const credentials = await this.getCredentials('twilioApi') as { accountSid: string; authType: 'authToken' | 'apiKey'; authToken: string; diff --git a/packages/nodes-base/nodes/Typeform/GenericFunctions.ts b/packages/nodes-base/nodes/Typeform/GenericFunctions.ts index c19c2ec2d8..688a0d715c 100644 --- a/packages/nodes-base/nodes/Typeform/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Typeform/GenericFunctions.ts @@ -65,7 +65,7 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('typeformApi'); + const credentials = await this.getCredentials('typeformApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/UProc/GenericFunctions.ts b/packages/nodes-base/nodes/UProc/GenericFunctions.ts index 42b2eb535a..b3c94d31b2 100644 --- a/packages/nodes-base/nodes/UProc/GenericFunctions.ts +++ b/packages/nodes-base/nodes/UProc/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function uprocApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('uprocApi'); + const credentials = await this.getCredentials('uprocApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/UnleashedSoftware/GenericFunctions.ts b/packages/nodes-base/nodes/UnleashedSoftware/GenericFunctions.ts index d6278bd57e..b5be8cede0 100644 --- a/packages/nodes-base/nodes/UnleashedSoftware/GenericFunctions.ts +++ b/packages/nodes-base/nodes/UnleashedSoftware/GenericFunctions.ts @@ -40,7 +40,7 @@ export async function unleashedApiRequest(this: IHookFunctions | IExecuteFunctio delete options.body; } - const credentials = this.getCredentials('unleashedSoftwareApi'); + const credentials = await this.getCredentials('unleashedSoftwareApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Uplead/GenericFunctions.ts b/packages/nodes-base/nodes/Uplead/GenericFunctions.ts index 668c78d36a..74b1a74050 100644 --- a/packages/nodes-base/nodes/Uplead/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Uplead/GenericFunctions.ts @@ -8,7 +8,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function upleadApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('upleadApi'); + const credentials = await this.getCredentials('upleadApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/UptimeRobot/GenericFunctions.ts b/packages/nodes-base/nodes/UptimeRobot/GenericFunctions.ts index 39d181224c..240051abf2 100644 --- a/packages/nodes-base/nodes/UptimeRobot/GenericFunctions.ts +++ b/packages/nodes-base/nodes/UptimeRobot/GenericFunctions.ts @@ -13,7 +13,7 @@ import { } from 'n8n-workflow'; export async function uptimeRobotApiRequest(this: IExecuteFunctions, method: string, resource: string, body: IDataObject = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}) { - const credentials = this.getCredentials('uptimeRobotApi'); + const credentials = await this.getCredentials('uptimeRobotApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Vero/GenericFunctions.ts b/packages/nodes-base/nodes/Vero/GenericFunctions.ts index faeded0600..1775f4f914 100644 --- a/packages/nodes-base/nodes/Vero/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Vero/GenericFunctions.ts @@ -7,7 +7,7 @@ import { import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; export async function veroApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('veroApi'); + const credentials = await this.getCredentials('veroApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Vonage/GenericFunctions.ts b/packages/nodes-base/nodes/Vonage/GenericFunctions.ts index 5cbdc40d39..9b010b9903 100644 --- a/packages/nodes-base/nodes/Vonage/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Vonage/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function vonageApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('vonageApi') as IDataObject; + const credentials = await this.getCredentials('vonageApi') as IDataObject; body.api_key = credentials.apiKey as string; diff --git a/packages/nodes-base/nodes/Webflow/GenericFunctions.ts b/packages/nodes-base/nodes/Webflow/GenericFunctions.ts index 8be810d11a..5629d918f9 100644 --- a/packages/nodes-base/nodes/Webflow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Webflow/GenericFunctions.ts @@ -47,7 +47,7 @@ export async function webflowApiRequest( } try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('webflowApi'); + const credentials = await this.getCredentials('webflowApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Webhook.node.ts b/packages/nodes-base/nodes/Webhook.node.ts index f51a0fb692..8d048628b3 100644 --- a/packages/nodes-base/nodes/Webhook.node.ts +++ b/packages/nodes-base/nodes/Webhook.node.ts @@ -369,7 +369,7 @@ export class Webhook implements INodeType { if (authentication === 'basicAuth') { // Basic authorization is needed to call webhook - const httpBasicAuth = this.getCredentials('httpBasicAuth'); + const httpBasicAuth = await this.getCredentials('httpBasicAuth'); if (httpBasicAuth === undefined || !httpBasicAuth.user || !httpBasicAuth.password) { // Data is not defined on node so can not authenticate @@ -389,7 +389,7 @@ export class Webhook implements INodeType { } } else if (authentication === 'headerAuth') { // Special header with value is needed to call webhook - const httpHeaderAuth = this.getCredentials('httpHeaderAuth'); + const httpHeaderAuth = await this.getCredentials('httpHeaderAuth'); if (httpHeaderAuth === undefined || !httpHeaderAuth.name || !httpHeaderAuth.value) { // Data is not defined on node so can not authenticate diff --git a/packages/nodes-base/nodes/Wekan/GenericFunctions.ts b/packages/nodes-base/nodes/Wekan/GenericFunctions.ts index 4a652f2f6d..50810f263b 100644 --- a/packages/nodes-base/nodes/Wekan/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Wekan/GenericFunctions.ts @@ -46,7 +46,7 @@ export async function getAuthorization( } export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('wekanApi'); + const credentials = await this.getCredentials('wekanApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Wise/GenericFunctions.ts b/packages/nodes-base/nodes/Wise/GenericFunctions.ts index 15e751c633..785a2097b4 100644 --- a/packages/nodes-base/nodes/Wise/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Wise/GenericFunctions.ts @@ -25,7 +25,7 @@ export async function wiseApiRequest( qs: IDataObject = {}, option: IDataObject = {}, ) { - const { apiToken, environment } = this.getCredentials('wiseApi') as { + const { apiToken, environment } = await this.getCredentials('wiseApi') as { apiToken: string, environment: 'live' | 'test', }; diff --git a/packages/nodes-base/nodes/Wise/Wise.node.ts b/packages/nodes-base/nodes/Wise/Wise.node.ts index 90f8146478..c985553645 100644 --- a/packages/nodes-base/nodes/Wise/Wise.node.ts +++ b/packages/nodes-base/nodes/Wise/Wise.node.ts @@ -426,7 +426,7 @@ export class Wise implements INodeType { // in sandbox, simulate transfer completion so that PDF receipt can be downloaded - const { environment } = this.getCredentials('wiseApi') as IDataObject; + const { environment } = await this.getCredentials('wiseApi') as IDataObject; if (environment === 'test') { for (const endpoint of ['processing', 'funds_converted', 'outgoing_payment_sent']) { diff --git a/packages/nodes-base/nodes/Wise/WiseTrigger.node.ts b/packages/nodes-base/nodes/Wise/WiseTrigger.node.ts index 6b458488ff..098cb9d83b 100644 --- a/packages/nodes-base/nodes/Wise/WiseTrigger.node.ts +++ b/packages/nodes-base/nodes/Wise/WiseTrigger.node.ts @@ -154,7 +154,7 @@ export class WiseTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { const req = this.getRequestObject(); const headers = this.getHeaderData() as IDataObject; - const credentials = this.getCredentials('wiseApi') as IDataObject; + const credentials = await this.getCredentials('wiseApi') as IDataObject; if (headers['x-test-notification'] === 'true') { const res = this.getResponseObject(); diff --git a/packages/nodes-base/nodes/WooCommerce/GenericFunctions.ts b/packages/nodes-base/nodes/WooCommerce/GenericFunctions.ts index 4416961a07..0096f76aa7 100644 --- a/packages/nodes-base/nodes/WooCommerce/GenericFunctions.ts +++ b/packages/nodes-base/nodes/WooCommerce/GenericFunctions.ts @@ -37,7 +37,7 @@ import { } from 'lodash'; export async function woocommerceApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('wooCommerceApi'); + const credentials = await this.getCredentials('wooCommerceApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/WooCommerce/WooCommerceTrigger.node.ts b/packages/nodes-base/nodes/WooCommerce/WooCommerceTrigger.node.ts index 6c4deb2e80..08359b5abe 100644 --- a/packages/nodes-base/nodes/WooCommerce/WooCommerceTrigger.node.ts +++ b/packages/nodes-base/nodes/WooCommerce/WooCommerceTrigger.node.ts @@ -132,7 +132,7 @@ export class WooCommerceTrigger implements INodeType { return false; }, async create(this: IHookFunctions): Promise { - const credentials = this.getCredentials('wooCommerceApi'); + const credentials = await this.getCredentials('wooCommerceApi'); const webhookUrl = this.getNodeWebhookUrl('default'); const webhookData = this.getWorkflowStaticData('node'); const event = this.getNodeParameter('event') as string; diff --git a/packages/nodes-base/nodes/Wordpress/GenericFunctions.ts b/packages/nodes-base/nodes/Wordpress/GenericFunctions.ts index 89eda9d98f..f42f0d4f34 100644 --- a/packages/nodes-base/nodes/Wordpress/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Wordpress/GenericFunctions.ts @@ -13,7 +13,7 @@ import { } from 'n8n-workflow'; export async function wordpressApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('wordpressApi'); + const credentials = await this.getCredentials('wordpressApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Wufoo/GenericFunctions.ts b/packages/nodes-base/nodes/Wufoo/GenericFunctions.ts index e84164f311..0963ee65b3 100644 --- a/packages/nodes-base/nodes/Wufoo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Wufoo/GenericFunctions.ts @@ -14,7 +14,7 @@ import { } from 'n8n-workflow'; export async function wufooApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('wufooApi'); + const credentials = await this.getCredentials('wufooApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Yourls/GenericFunctions.ts b/packages/nodes-base/nodes/Yourls/GenericFunctions.ts index 9d49a8b4ab..2f10e8b81e 100644 --- a/packages/nodes-base/nodes/Yourls/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Yourls/GenericFunctions.ts @@ -14,7 +14,7 @@ import { export async function yourlsApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, body: any = {}, qs: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('yourlsApi') as IDataObject; + const credentials = await this.getCredentials('yourlsApi') as IDataObject; qs.signature = credentials.signature as string; qs.format = 'json'; diff --git a/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts b/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts index a7048b6ad6..b03f1c6ebd 100644 --- a/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts @@ -36,7 +36,7 @@ export async function zendeskApiRequest(this: IHookFunctions | IExecuteFunctions try { if (authenticationMethod === 'apiToken') { - const credentials = this.getCredentials('zendeskApi'); + const credentials = await this.getCredentials('zendeskApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); @@ -48,7 +48,7 @@ export async function zendeskApiRequest(this: IHookFunctions | IExecuteFunctions return await this.helpers.request!(options); } else { - const credentials = this.getCredentials('zendeskOAuth2Api'); + const credentials = await this.getCredentials('zendeskOAuth2Api'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Zoho/GenericFunctions.ts b/packages/nodes-base/nodes/Zoho/GenericFunctions.ts index fa862de03b..5b4ae69755 100644 --- a/packages/nodes-base/nodes/Zoho/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zoho/GenericFunctions.ts @@ -43,7 +43,7 @@ export async function zohoApiRequest( qs: IDataObject = {}, uri?: string, ) { - const { oauthTokenData } = this.getCredentials('zohoOAuth2Api') as ZohoOAuth2ApiCredentials; + const { oauthTokenData } = await this.getCredentials('zohoOAuth2Api') as ZohoOAuth2ApiCredentials; const options: OptionsWithUri = { body: { diff --git a/packages/nodes-base/nodes/Zoom/GenericFunctions.ts b/packages/nodes-base/nodes/Zoom/GenericFunctions.ts index c85384274d..306a9848e7 100644 --- a/packages/nodes-base/nodes/Zoom/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zoom/GenericFunctions.ts @@ -36,7 +36,7 @@ export async function zoomApiRequest(this: IExecuteFunctions | IExecuteSingleFun try { if (authenticationMethod === 'accessToken') { - const credentials = this.getCredentials('zoomApi'); + const credentials = await this.getCredentials('zoomApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } diff --git a/packages/nodes-base/nodes/Zulip/GenericFunctions.ts b/packages/nodes-base/nodes/Zulip/GenericFunctions.ts index a922f77cd6..4ee0d1e787 100644 --- a/packages/nodes-base/nodes/Zulip/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zulip/GenericFunctions.ts @@ -15,7 +15,7 @@ import { export async function zulipApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('zulipApi'); + const credentials = await this.getCredentials('zulipApi'); if (credentials === undefined) { throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); diff --git a/packages/nodes-base/nodes/Zulip/Zulip.node.ts b/packages/nodes-base/nodes/Zulip/Zulip.node.ts index 5d77e2f6c9..9281e90dc9 100644 --- a/packages/nodes-base/nodes/Zulip/Zulip.node.ts +++ b/packages/nodes-base/nodes/Zulip/Zulip.node.ts @@ -209,7 +209,7 @@ export class Zulip implements INodeType { } //https://zulipchat.com/api/upload-file if (operation === 'updateFile') { - const credentials = this.getCredentials('zulipApi'); + const credentials = await this.getCredentials('zulipApi'); const binaryProperty = this.getNodeParameter('dataBinaryProperty', i) as string; if (items[i].binary === undefined) { throw new NodeOperationError(this.getNode(), 'No binary data exists on item!'); diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index b040ac1db8..71c156fab4 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -95,15 +95,13 @@ export interface ICredentialsExpressionResolveValues { export abstract class ICredentialsHelper { encryptionKey: string; - workflowCredentials: IWorkflowCredentials; - constructor(workflowCredentials: IWorkflowCredentials, encryptionKey: string) { + constructor(encryptionKey: string) { this.encryptionKey = encryptionKey; - this.workflowCredentials = workflowCredentials; } - abstract getCredentials(name: string, type: string): ICredentials; - abstract getDecrypted(name: string, type: string, mode: WorkflowExecuteMode, raw?: boolean, expressionResolveValues?: ICredentialsExpressionResolveValues): ICredentialDataDecryptedObject; + abstract getCredentials(name: string, type: string): Promise; + abstract getDecrypted(name: string, type: string, mode: WorkflowExecuteMode, raw?: boolean, expressionResolveValues?: ICredentialsExpressionResolveValues): Promise; abstract updateCredentials(name: string, type: string, data: ICredentialDataDecryptedObject): Promise; } @@ -212,7 +210,7 @@ export interface IExecuteFunctions { evaluateExpression(expression: string, itemIndex: number): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[]; executeWorkflow(workflowInfo: IExecuteWorkflowInfo, inputData?: INodeExecutionData[]): Promise; // tslint:disable-line:no-any getContext(type: string): IContextObject; - getCredentials(type: string, itemIndex?: number): ICredentialDataDecryptedObject | undefined; + getCredentials(type: string, itemIndex?: number): Promise; getInputData(inputIndex?: number, inputName?: string): INodeExecutionData[]; getMode(): WorkflowExecuteMode; getNode(): INode; @@ -234,7 +232,7 @@ export interface IExecuteSingleFunctions { continueOnFail(): boolean; evaluateExpression(expression: string, itemIndex: number | undefined): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[]; getContext(type: string): IContextObject; - getCredentials(type: string): ICredentialDataDecryptedObject | undefined; + getCredentials(type: string): Promise; getInputData(inputIndex?: number, inputName?: string): INodeExecutionData; getMode(): WorkflowExecuteMode; getNode(): INode; @@ -255,7 +253,7 @@ export interface IExecuteWorkflowInfo { } export interface ILoadOptionsFunctions { - getCredentials(type: string): ICredentialDataDecryptedObject | undefined; + getCredentials(type: string): Promise; getNode(): INode; getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any getCurrentNodeParameter(parameterName: string): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object | undefined; @@ -268,7 +266,7 @@ export interface ILoadOptionsFunctions { } export interface IHookFunctions { - getCredentials(type: string): ICredentialDataDecryptedObject | undefined; + getCredentials(type: string): Promise; getMode(): WorkflowExecuteMode; getActivationMode(): WorkflowActivateMode; getNode(): INode; @@ -286,7 +284,7 @@ export interface IHookFunctions { export interface IPollFunctions { __emit(data: INodeExecutionData[][]): void; - getCredentials(type: string): ICredentialDataDecryptedObject | undefined; + getCredentials(type: string): Promise; getMode(): WorkflowExecuteMode; getActivationMode(): WorkflowActivateMode; getNode(): INode; @@ -302,7 +300,7 @@ export interface IPollFunctions { export interface ITriggerFunctions { emit(data: INodeExecutionData[][]): void; - getCredentials(type: string): ICredentialDataDecryptedObject | undefined; + getCredentials(type: string): Promise; getMode(): WorkflowExecuteMode; getActivationMode(): WorkflowActivateMode; getNode(): INode; @@ -318,7 +316,7 @@ export interface ITriggerFunctions { export interface IWebhookFunctions { getBodyData(): IDataObject; - getCredentials(type: string): ICredentialDataDecryptedObject | undefined; + getCredentials(type: string): Promise; getHeaderData(): object; getMode(): WorkflowExecuteMode; getNode(): INode; @@ -739,7 +737,6 @@ export interface IWorkflowExecuteHooks { } export interface IWorkflowExecuteAdditionalData { - credentials: IWorkflowCredentials; credentialsHelper: ICredentialsHelper; encryptionKey: string; executeWorkflow: (workflowInfo: IExecuteWorkflowInfo, additionalData: IWorkflowExecuteAdditionalData, inputData?: INodeExecutionData[], parentExecutionId?: string, loadedWorkflowData?: IWorkflowBase, loadedRunData?: any) => Promise; // tslint:disable-line:no-any From 0a5b9ed1534f2e285dd825b5822010b3f83c54f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 20 Aug 2021 23:36:33 +0200 Subject: [PATCH 07/30] :zap: Replace coda logo (#2107) --- packages/nodes-base/nodes/Coda/coda.svg | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/nodes-base/nodes/Coda/coda.svg b/packages/nodes-base/nodes/Coda/coda.svg index a3e59ee319..1d3c64f327 100644 --- a/packages/nodes-base/nodes/Coda/coda.svg +++ b/packages/nodes-base/nodes/Coda/coda.svg @@ -1 +1,11 @@ - \ No newline at end of file + + + + + + From 199377e183399725819b6119f5ed80d2bbb9cd62 Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Fri, 20 Aug 2021 23:48:02 +0200 Subject: [PATCH 08/30] :zap: Replace glob-promise with fast-glob (#2096) Co-authored-by: lublak --- packages/cli/commands/import/credentials.ts | 2 +- packages/cli/commands/import/workflow.ts | 2 +- packages/cli/package.json | 2 +- packages/cli/src/LoadNodesAndCredentials.ts | 4 ++-- packages/nodes-base/nodes/ReadBinaryFiles.node.ts | 2 +- packages/nodes-base/package.json | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/cli/commands/import/credentials.ts b/packages/cli/commands/import/credentials.ts index af2d7e0d46..38835ed7fd 100644 --- a/packages/cli/commands/import/credentials.ts +++ b/packages/cli/commands/import/credentials.ts @@ -21,7 +21,7 @@ import { } from 'n8n-workflow'; import * as fs from 'fs'; -import * as glob from 'glob-promise'; +import * as glob from 'fast-glob'; import * as path from 'path'; export class ImportCredentialsCommand extends Command { diff --git a/packages/cli/commands/import/workflow.ts b/packages/cli/commands/import/workflow.ts index 65ddb77000..2d9a3ac136 100644 --- a/packages/cli/commands/import/workflow.ts +++ b/packages/cli/commands/import/workflow.ts @@ -16,7 +16,7 @@ import { } from 'n8n-workflow'; import * as fs from 'fs'; -import * as glob from 'glob-promise'; +import * as glob from 'fast-glob'; import * as path from 'path'; import { UserSettings, diff --git a/packages/cli/package.json b/packages/cli/package.json index 04b803526b..55a8b62c70 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -98,8 +98,8 @@ "csrf": "^3.1.0", "dotenv": "^8.0.0", "express": "^4.16.4", + "fast-glob": "^3.2.5", "flatted": "^2.0.0", - "glob-promise": "^3.4.0", "google-timezones-json": "^1.0.2", "inquirer": "^7.0.1", "json-diff": "^0.5.4", diff --git a/packages/cli/src/LoadNodesAndCredentials.ts b/packages/cli/src/LoadNodesAndCredentials.ts index 777fa0bb00..037293dfc2 100644 --- a/packages/cli/src/LoadNodesAndCredentials.ts +++ b/packages/cli/src/LoadNodesAndCredentials.ts @@ -22,8 +22,8 @@ import { readdir as fsReaddir, readFile as fsReadFile, stat as fsStat, - } from 'fs/promises'; -import * as glob from 'glob-promise'; +} from 'fs/promises'; +import * as glob from 'fast-glob'; import * as path from 'path'; const CUSTOM_NODES_CATEGORY = 'Custom Nodes'; diff --git a/packages/nodes-base/nodes/ReadBinaryFiles.node.ts b/packages/nodes-base/nodes/ReadBinaryFiles.node.ts index 509402bb21..af7b3f9b12 100644 --- a/packages/nodes-base/nodes/ReadBinaryFiles.node.ts +++ b/packages/nodes-base/nodes/ReadBinaryFiles.node.ts @@ -4,7 +4,7 @@ import { INodeType, INodeTypeDescription, } from 'n8n-workflow'; -import * as glob from 'glob-promise'; +import * as glob from 'fast-glob'; import * as path from 'path'; import { diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 93508d7133..de42d71c59 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -652,9 +652,9 @@ "cron": "^1.7.2", "eventsource": "^1.0.7", "fflate": "^0.7.0", + "fast-glob": "^3.2.5", "formidable": "^1.2.1", "get-system-fonts": "^2.0.2", - "glob-promise": "^3.4.0", "gm": "^1.23.1", "iconv-lite": "^0.6.2", "ics": "^2.27.0", From 12417ea323fd9acb2d5d67e57e2ff2bfa15272f6 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Sat, 21 Aug 2021 06:53:06 -0400 Subject: [PATCH 09/30] :sparkles: Add Form.io Trigger (#2064) * Initial commit n8n smartsheet and formio nodes 1. created smarsheet node that can add new rew to a particular smarsheet. 2. created formio trigger node which will listen to form.io form submit event and process data. * Added coloum mapping logic form.io field label to smarsheet column title. API and smartsheet sheetId configuration added to smartsheet node. * Added smartsheet api credentials and used it in smartsheet node. * Added logos to the form.io and smartsheet nodes. Removed smartsheet and form.io npm dependencies from the nodes. Added type check for the variables used. fixed tslint errors in the created nodes. * :zap: Improvements to #1943 * :zap: Improvements * :zap: Improvements * :zap: Some fixes and improvements Co-authored-by: Parthiban Chandrasekar Co-authored-by: Jan Oberhauser --- .../credentials/FormIoApi.credentials.ts | 57 +++++ .../nodes/FormIo/FormIoTrigger.node.ts | 205 ++++++++++++++++++ .../nodes/FormIo/GenericFunctions.ts | 84 +++++++ packages/nodes-base/nodes/FormIo/formio.svg | 1 + packages/nodes-base/package.json | 2 + 5 files changed, 349 insertions(+) create mode 100644 packages/nodes-base/credentials/FormIoApi.credentials.ts create mode 100644 packages/nodes-base/nodes/FormIo/FormIoTrigger.node.ts create mode 100644 packages/nodes-base/nodes/FormIo/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/FormIo/formio.svg diff --git a/packages/nodes-base/credentials/FormIoApi.credentials.ts b/packages/nodes-base/credentials/FormIoApi.credentials.ts new file mode 100644 index 0000000000..50439cd738 --- /dev/null +++ b/packages/nodes-base/credentials/FormIoApi.credentials.ts @@ -0,0 +1,57 @@ +import { + ICredentialType, + INodeProperties, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class FormIoApi implements ICredentialType { + name = 'formIoApi'; + displayName = 'Form.io API'; + properties: INodeProperties[] = [ + { + displayName: 'Environment', + name: 'environment', + type: 'options', + default: 'cloudHosted', + options: [ + { + name: 'Cloud-hosted', + value: 'cloudHosted', + }, + { + name: 'Self-hosted', + value: 'selfHosted', + }, + ], + }, + { + displayName: 'Self-hosted domain', + name: 'domain', + type: 'string', + default: '', + placeholder: 'https://www.mydomain.com', + displayOptions: { + show: { + environment: [ + 'selfHosted', + ], + }, + }, + }, + { + displayName: 'Email', + name: 'email', + type: 'string' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Password', + name: 'password', + type: 'string' as NodePropertyTypes, + typeOptions: { + password: true, + }, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/FormIo/FormIoTrigger.node.ts b/packages/nodes-base/nodes/FormIo/FormIoTrigger.node.ts new file mode 100644 index 0000000000..30cc69e3b8 --- /dev/null +++ b/packages/nodes-base/nodes/FormIo/FormIoTrigger.node.ts @@ -0,0 +1,205 @@ +import { + IHookFunctions, + IWebhookFunctions, +} from 'n8n-core'; + +import { + ILoadOptionsFunctions, + INodePropertyOptions, + INodeType, + INodeTypeDescription, + IWebhookResponseData, +} from 'n8n-workflow'; + +import { + formIoApiRequest, +} from './GenericFunctions'; + +export class FormIoTrigger implements INodeType { + description: INodeTypeDescription = { + displayName: 'Form.io Trigger', + name: 'formIoTrigger', + icon: 'file:formio.svg', + group: ['trigger'], + version: 1, + subtitle: '={{$parameter["event"]}}', + description: 'Handle form.io events via webhooks', + defaults: { + name: 'Form.io Trigger', + color: '#6ad7b9', + }, + inputs: [], + outputs: ['main'], + credentials: [ + { + name: 'formIoApi', + required: true, + }, + ], + webhooks: [ + { + name: 'default', + httpMethod: 'POST', + responseMode: 'onReceived', + path: 'webhook', + }, + ], + properties: [ + { + displayName: 'Project Name/ID', + name: 'projectId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getProjects', + }, + required: true, + default: '', + description: `Choose from the list or specify an ID. You can also specify the ID using an expression` + }, + { + displayName: 'Form Name/ID', + name: 'formId', + type: 'options', + typeOptions: { + loadOptionsDependsOn: [ + 'projectId', + ], + loadOptionsMethod: 'getForms', + }, + required: true, + default: '', + description: `Choose from the list or specify an ID. You can also specify the ID using an expression` + }, + { + displayName: 'Trigger Events', + name: 'events', + type: 'multiOptions', + options: [ + { + name: 'Submission Created', + value: 'create', + }, + { + name: 'Submission Updated', + value: 'update', + }, + ], + required: true, + default: '', + }, + { + displayName: 'Simplify Response', + name: 'simple', + type: 'boolean', + default: true, + description: 'Return a simplified version of the response instead of the raw data', + }, + ], + }; + + methods = { + loadOptions: { + async getProjects(this: ILoadOptionsFunctions): Promise { + const projects = await formIoApiRequest.call(this, 'GET', '/project', {}); + const returnData: INodePropertyOptions[] = []; + for (const project of projects) { + returnData.push({ + name: project.title, + value: project._id, + }); + } + return returnData; + }, + async getForms(this: ILoadOptionsFunctions): Promise { + const projectId = this.getCurrentNodeParameter('projectId') as string; + const forms = await formIoApiRequest.call(this, 'GET', `/project/${projectId}/form`, {}); + const returnData: INodePropertyOptions[] = []; + for (const form of forms) { + returnData.push({ + name: form.title, + value: form._id, + }); + } + return returnData; + }, + }, + }; + + // @ts-ignore + webhookMethods = { + default: { + async checkExists(this: IHookFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node'); + const webhookUrl = this.getNodeWebhookUrl('default'); + const formId = this.getNodeParameter('formId') as string; + const projectId = this.getNodeParameter('projectId') as string; + const method = this.getNodeParameter('events') as string[]; + const actions = await formIoApiRequest.call(this, 'GET', `/project/${projectId}/form/${formId}/action`); + for (const action of actions) { + if (action.name === 'webhook') { + if (action.settings.url === webhookUrl && + // tslint:disable-next-line: no-any + (action.method.length === method.length && action.method.every((value: any) => method.includes(value)))) { + webhookData.webhookId = action._id; + return true; + } + } + } + return false; + }, + + async create(this: IHookFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node'); + const formId = this.getNodeParameter('formId') as string; + const projectId = this.getNodeParameter('projectId') as string; + const webhookUrl = this.getNodeWebhookUrl('default') as string; + const method = this.getNodeParameter('events') as string[]; + const payload = { + data: { + name: `webhook`, + title: `webhook-n8n:${webhookUrl}`, + method, + handler: [ + 'after', + ], + priority: 0, + settings: { + method: 'post', + block: false, + url: webhookUrl, + }, + condition: { + field: 'submit', + }, + }, + }; + const webhook = await formIoApiRequest.call(this, 'POST', `/project/${projectId}/form/${formId}/action`, payload); + webhookData.webhookId = webhook._id; + return true; + }, + + async delete(this: IHookFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node'); + const formId = this.getNodeParameter('formId') as string; + const projectId = this.getNodeParameter('projectId') as string; + await formIoApiRequest.call(this, 'DELETE', `/project/${projectId}/form/${formId}/action/${webhookData.webhookId}`); + delete webhookData.webhookId; + return true; + }, + }, + }; + + async webhook(this: IWebhookFunctions): Promise { + const req = this.getRequestObject(); + const simple = this.getNodeParameter('simple') as boolean; + let response = req.body.request; + if (simple === true) { + response = response.data; + } + return { + workflowData: [ + this.helpers.returnJsonArray(response), + ], + }; + } +} diff --git a/packages/nodes-base/nodes/FormIo/GenericFunctions.ts b/packages/nodes-base/nodes/FormIo/GenericFunctions.ts new file mode 100644 index 0000000000..ae42a4f28f --- /dev/null +++ b/packages/nodes-base/nodes/FormIo/GenericFunctions.ts @@ -0,0 +1,84 @@ +import { + IExecuteFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; + +import { + IDataObject, + IHookFunctions, + IWebhookFunctions, + NodeApiError, +} from 'n8n-workflow'; + + +interface IFormIoCredentials { + environment: 'cloudHosted' | ' selfHosted'; + domain?: string; + email: string, + password: string, +} + +/** + * Method has the logic to get jwt token from Form.io + * @param this + */ +async function getToken(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, credentials: IFormIoCredentials) { + const base = credentials.domain || 'https://formio.form.io'; + const options = { + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + body: { + data: { + email: credentials.email, + password: credentials.password, + }, + }, + uri: `${base}/user/login`, + json: true, + resolveWithFullResponse: true, + }; + + console.log('options'); + console.log(JSON.stringify(options, null, 2)); + + try { + const responseObject = await this.helpers.request!(options); + return responseObject.headers['x-jwt-token']; + } catch (error) { + throw new Error(`Authentication Failed for Form.io. Please provide valid credentails/ endpoint details`); + } +} + +/** + * Method will call register or list webhooks based on the passed method in the parameter + * @param this + * @param method + */ +export async function formIoApiRequest(this: IHookFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, endpoint: string, body = {}, qs = {}): Promise { // tslint:disable-line:no-any + + const credentials = await this.getCredentials('formIoApi') as unknown as IFormIoCredentials; + + const token = await getToken.call(this, credentials); + + const base = credentials.domain || 'https://api.form.io'; + + const options = { + headers: { + 'Content-Type': 'application/json', + 'x-jwt-token': token, + }, + method, + body, + qs, + uri: `${base}${endpoint}`, + json: true, + }; + + try { + return await this.helpers.request!.call(this, options); + } catch (error) { + throw new NodeApiError(this.getNode(), error); + } +} diff --git a/packages/nodes-base/nodes/FormIo/formio.svg b/packages/nodes-base/nodes/FormIo/formio.svg new file mode 100644 index 0000000000..0887bca61d --- /dev/null +++ b/packages/nodes-base/nodes/FormIo/formio.svg @@ -0,0 +1 @@ +favicon-3 \ No newline at end of file diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index de42d71c59..67c7c6f966 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -90,6 +90,7 @@ "dist/credentials/FileMaker.credentials.js", "dist/credentials/FlowApi.credentials.js", "dist/credentials/Ftp.credentials.js", + "dist/credentials/FormIoApi.credentials.js", "dist/credentials/GetResponseApi.credentials.js", "dist/credentials/GetResponseOAuth2Api.credentials.js", "dist/credentials/GhostAdminApi.credentials.js", @@ -382,6 +383,7 @@ "dist/nodes/Ftp.node.js", "dist/nodes/Freshdesk/Freshdesk.node.js", "dist/nodes/FreshworksCrm/FreshworksCrm.node.js", + "dist/nodes/FormIo/FormIoTrigger.node.js", "dist/nodes/Flow/Flow.node.js", "dist/nodes/Flow/FlowTrigger.node.js", "dist/nodes/Function.node.js", From 5a179cd5aebb57d9f5017bb71544370af4953327 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 21 Aug 2021 14:11:32 +0200 Subject: [PATCH 10/30] :sparkles: Implement Wait functionality (#1817) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor saving * refactor api layer to be stateless * refactor header details * set variable for menu height * clean up scss * clean up indentation * clean up dropdown impl * refactor no tags view * split away header * Fix tslint issues * Refactor tag manager * add tags to patch request * clean up scss * :zap: Refactor types to entities * fix issues * update no workflow error * clean up tagscontainer * use getters instead of state * remove imports * use custom colors * clean up tags container * clean up dropdown * clean up focusoncreate * :zap: Ignore mistaken ID in POST /workflows * :zap: Fix undefined tag ID in PATCH /workflows * :zap: Shorten response for POST /tags * remove scss mixins * clean up imports * :zap: Implement validation with class-validator * address ivan's comments * implement modals * Fix lint issues * fix disabling shortcuts * fix focus issues * fix focus issues * fix focus issues with modal * fix linting issues * use dispatch * use constants for modal keys * fix focus * fix lint issues * remove unused prop * add modal root * fix lint issues * remove unused methods * fix shortcut * remove max width * :zap: Fix duplicate entry error for pg and MySQL * update rename messaging * update order of buttons * fix firefox overflow on windows * fix dropdown height * :hammer: refactor tag crud controllers * 🧹 remove unused imports * use variable for number of items * fix dropdown spacing * :zap: Restore type to fix build * :zap: Fix post-refactor PATCH /workflows/:id * :zap: Fix PATCH /workflows/:id for zero tags * :zap: Fix usage count becoming stringified * address max's comments * fix filter spacing * fix blur bug * address most of ivan's comments * address tags type concern * remove defaults * :zap: return tag id as string * :hammer: add hooks to tag CUD operations * 🏎 simplify timestamp pruning * remove blur event * fix onblur bug * :zap: Fix fs import to fix build * address max's comments * implement responsive tag container * fix lint issues * update tag limits * address ivan's comments * remove rename, refactor header, implement new designs for save, remove responsive tag container * update styling * update styling * implement responsive tag container * implement header tags edit * implement header tags edit * fix lint issues * implement expandable input * minor fixes * minor fixes * use variable * rename save as * duplicate fixes * minor edit fixes * lint fixes * style fixes * hook up saving name * hook up tags * clean up impl * fix dirty state bug * update limit * update notification messages * on click outside * fix minor bug with count * lint fixes * handle minor edge cases * handle minor edge cases * handle minor bugs; fix firefox dropdown issue * Fix min width * apply tags only after api success * remove count fix * clean up workflow tags impl, fix tags delete bug * fix minor issue * fix minor spacing issue * disable wrap for ops * fix viewport root; save on click in dropdown * save button loading when saving name/tags * implement max width on tags container * implement cleaner create experience * disable edit while updating * codacy hex color * refactor tags container * fix clickability * fix workflow open and count * clean up structure * fix up lint issues * fix button size * increase workflow name limit for larger screen * tslint fixes * disable responsiveness for workflow modal * rename event * change min width for tags * clean up pr * address max's comments on styles * remove success toasts * add hover mode to name * minor fixes * refactor name preview * fix name input not to jiggle * finish up name input * Fix up add tags * clean up param * clean up scss * fix resizing name * fix resizing name * fix resize bug * clean up edit spacing * ignore on esc * fix input bug * focus input on clear * build * fix up add tags clickablity * remove scrollbars * move into folders * clean up multiple patch req * remove padding top from edit * update tags on enter * build * rollout blur on enter behavior * rollout esc behavior * fix tags bug when duplicating tags * move key to reload tags * update header spacing * build * update hex case * refactor workflow title * remove unusued prop * keep focus on error, fix bug on error * Fix bug with name / tags toggle on error * fix connection push bug * :spakles: Implement wait functionality * :bug: Do not delete waiting executions with prune * :zap: Improve SQLite migration to not lose execution data anymore * :zap: Make it possible to restart waiting execution via webhook * :zap: Add missing file * :bug: Some more merge fixes * :zap: Do not show error for Wait-Nodes if in time-mode * :zap: Make $executionId available in expressions * :shirt: Fix lint issue * :shirt: Fix lint issue * :shirt: Fix lint issue * :zap: Set the unlimited sleep time as a variable * :zap: Add also sleeping webhook path to config * :zap: Make it possible to retrieve restartUrl in workflow * :zap: Add authentication to Wait-Node in Webhook-Mode * :zap: Return 404 when trying to restart execution via webhook which does not support it * :sparkles: Make it possible to set absolute time on Wait-Node * :zap: Remove not needed imports * :zap: Fix description format * :sparkles: Implement missing webhook features on Wait-Node * :zap: Display webhook variable in NodeWebhooks * :zap: Include also date in displayed sleep time * :zap: Make it possible to see sleep time on node * :zap: Make sure that no executions does get executed twice * :zap: Add comment * :zap: Further improvements * :zap: Make Wait-Node easier to use * :sparkles: Add support for "notice" parameter type * Fixing wait node to work with queue, improved logging and execution view * Added support for mysql and pg * :sparkles: Add support for webhook postfix path * :sparkles: Make it possible to stop sleeping executions * :zap: Fix issue with webhook paths in not webhook mode * :zap: Remove not needed console.log * :zap: Update TODOs * :zap: Increase min time of workflow staying active to descrease possible issue with overlap * :shirt: Fix lint issue * :bug: Fix issues with webhooks * :zap: Make error message clearer * :zap: Fix issue with missing execution ID in scaling mode * Fixed execution list to correctly display waiting executins * Feature: enable webhook wait workflows to continue after specified time * Fixed linting * :zap: Improve waiting description text * :zap: Fix parameter display issue and rename * :zap: Remove comment * :zap: Do not display webhooks on Wait-Node * Changed wording from restart to resume on wait node * Fixed wording and inconsistent screen when changing resume modes * Removed dots from the descriptions * Changed docs url and renaming postfix to suffix * Changed names from sleep to wait * :zap: Apply suggestions from ben Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com> * Some fixes by Ben * :zap: Remove console.logs * :zap: Fixes and improvements Co-authored-by: Mutasem Co-authored-by: Iván Ovejero Co-authored-by: Ben Hesseldieck Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com> Co-authored-by: Omar Ajoue --- packages/cli/commands/start.ts | 5 +- packages/cli/commands/worker.ts | 3 +- packages/cli/config/index.ts | 6 + packages/cli/src/ActiveExecutions.ts | 54 +- packages/cli/src/ActiveWorkflowRunner.ts | 6 +- packages/cli/src/CredentialsHelper.ts | 4 +- packages/cli/src/Interfaces.ts | 4 + packages/cli/src/ResponseHelper.ts | 2 + packages/cli/src/Server.ts | 130 ++- packages/cli/src/TestWebhooks.ts | 9 +- packages/cli/src/WaitTracker.ts | 181 ++++ packages/cli/src/WaitingWebhooks.ts | 117 +++ packages/cli/src/WebhookHelpers.ts | 46 +- packages/cli/src/WebhookServer.ts | 5 + .../cli/src/WorkflowExecuteAdditionalData.ts | 24 +- packages/cli/src/WorkflowRunner.ts | 24 +- packages/cli/src/WorkflowRunnerProcess.ts | 1 + .../src/databases/entities/ExecutionEntity.ts | 4 + .../migrations/1626183952959-AddWaitColumn.ts | 22 + .../src/databases/mysqldb/migrations/index.ts | 2 + .../migrations/1626176912946-AddwaitTill.ts | 31 + .../databases/postgresdb/migrations/index.ts | 2 + .../migrations/1621707690587-AddWaitColumn.ts | 31 + .../src/databases/sqlite/migrations/index.ts | 2 + packages/cli/src/index.ts | 2 + packages/core/src/Constants.ts | 2 + packages/core/src/NodeExecuteFunctions.ts | 65 +- packages/core/src/WorkflowExecute.ts | 22 +- packages/core/test/Helpers.ts | 1 + packages/editor-ui/src/Interface.ts | 1 + .../components/DuplicateWorkflowDialog.vue | 4 +- .../src/components/ExecutionsList.vue | 37 +- .../ExpandableInput/ExpandableInputBase.vue | 2 +- .../src/components/InlineTextEdit.vue | 4 +- .../ExecutionDetails/ExecutionDetails.vue | 20 +- .../src/components/MainHeader/MainHeader.vue | 2 +- .../components/MainHeader/WorkflowDetails.vue | 8 +- packages/editor-ui/src/components/Modal.vue | 2 +- packages/editor-ui/src/components/Node.vue | 40 +- .../editor-ui/src/components/NodeWebhooks.vue | 13 +- .../src/components/ParameterInputList.vue | 13 + .../src/components/PushConnectionTracker.vue | 2 +- .../editor-ui/src/components/TagsDropdown.vue | 2 +- .../components/TagsManager/TagsManager.vue | 10 +- .../src/components/VariableSelector.vue | 12 +- .../src/components/mixins/nodeHelpers.ts | 18 +- .../src/components/mixins/pushConnection.ts | 10 +- .../src/components/mixins/workflowHelpers.ts | 15 +- packages/editor-ui/src/constants.ts | 5 +- packages/editor-ui/src/main.ts | 6 +- .../nodes/FormIo/FormIoTrigger.node.ts | 4 +- .../nodes/FormIo/GenericFunctions.ts | 8 +- packages/nodes-base/nodes/Wait.node.ts | 887 ++++++++++++++++++ packages/nodes-base/package.json | 1 + packages/workflow/src/Expression.ts | 23 +- packages/workflow/src/Interfaces.ts | 15 +- packages/workflow/src/NodeHelpers.ts | 28 +- packages/workflow/src/WorkflowDataProxy.ts | 12 +- packages/workflow/test/Workflow.test.ts | 4 +- 59 files changed, 1823 insertions(+), 192 deletions(-) create mode 100644 packages/cli/src/WaitTracker.ts create mode 100644 packages/cli/src/WaitingWebhooks.ts create mode 100644 packages/cli/src/databases/mysqldb/migrations/1626183952959-AddWaitColumn.ts create mode 100644 packages/cli/src/databases/postgresdb/migrations/1626176912946-AddwaitTill.ts create mode 100644 packages/cli/src/databases/sqlite/migrations/1621707690587-AddWaitColumn.ts create mode 100644 packages/nodes-base/nodes/Wait.node.ts diff --git a/packages/cli/commands/start.ts b/packages/cli/commands/start.ts index bb6e64f56f..d2dbfe5a97 100644 --- a/packages/cli/commands/start.ts +++ b/packages/cli/commands/start.ts @@ -22,10 +22,11 @@ import { NodeTypes, Server, TestWebhooks, + WaitTracker, } from '../src'; import { IDataObject } from 'n8n-workflow'; -import { +import { getLogger, } from '../src/Logger'; @@ -284,6 +285,8 @@ export class Start extends Command { activeWorkflowRunner = ActiveWorkflowRunner.getInstance(); await activeWorkflowRunner.init(); + const waitTracker = WaitTracker(); + const editorUrl = GenericHelpers.getBaseUrl(); this.log(`\nEditor is now accessible via:\n${editorUrl}`); diff --git a/packages/cli/commands/worker.ts b/packages/cli/commands/worker.ts index b5ce727ceb..6e43857d34 100644 --- a/packages/cli/commands/worker.ts +++ b/packages/cli/commands/worker.ts @@ -37,7 +37,7 @@ import { WorkflowExecuteAdditionalData, } from '../src'; -import { +import { getLogger, } from '../src/Logger'; @@ -150,6 +150,7 @@ export class Worker extends Command { const additionalData = await WorkflowExecuteAdditionalData.getBase(undefined, executionTimeoutTimestamp); additionalData.hooks = WorkflowExecuteAdditionalData.getWorkflowHooksWorkerExecuter(currentExecutionDb.mode, job.data.executionId, currentExecutionDb.workflowData, { retryOf: currentExecutionDb.retryOf as string }); + additionalData.executionId = jobData.executionId; let workflowExecute: WorkflowExecute; let workflowRun: PCancelable; diff --git a/packages/cli/config/index.ts b/packages/cli/config/index.ts index 476cbbcfa7..0a5273799b 100644 --- a/packages/cli/config/index.ts +++ b/packages/cli/config/index.ts @@ -489,6 +489,12 @@ const config = convict({ env: 'N8N_ENDPOINT_WEBHOOK', doc: 'Path for webhook endpoint', }, + webhookWaiting: { + format: String, + default: 'webhook-waiting', + env: 'N8N_ENDPOINT_WEBHOOK_WAIT', + doc: 'Path for waiting-webhook endpoint', + }, webhookTest: { format: String, default: 'webhook-test', diff --git a/packages/cli/src/ActiveExecutions.ts b/packages/cli/src/ActiveExecutions.ts index 8a1094b685..3741ccd19e 100644 --- a/packages/cli/src/ActiveExecutions.ts +++ b/packages/cli/src/ActiveExecutions.ts @@ -35,31 +35,43 @@ export class ActiveExecutions { * @returns {string} * @memberof ActiveExecutions */ - async add(executionData: IWorkflowExecutionDataProcess, process?: ChildProcess): Promise { + async add(executionData: IWorkflowExecutionDataProcess, process?: ChildProcess, executionId?: string): Promise { - const fullExecutionData: IExecutionDb = { - data: executionData.executionData!, - mode: executionData.executionMode, - finished: false, - startedAt: new Date(), - workflowData: executionData.workflowData, - }; + if (executionId === undefined) { + // Is a new execution so save in DB - if (executionData.retryOf !== undefined) { - fullExecutionData.retryOf = executionData.retryOf.toString(); + const fullExecutionData: IExecutionDb = { + data: executionData.executionData!, + mode: executionData.executionMode, + finished: false, + startedAt: new Date(), + workflowData: executionData.workflowData, + }; + + if (executionData.retryOf !== undefined) { + fullExecutionData.retryOf = executionData.retryOf.toString(); + } + + if (executionData.workflowData.id !== undefined && WorkflowHelpers.isWorkflowIdValid(executionData.workflowData.id.toString()) === true) { + fullExecutionData.workflowId = executionData.workflowData.id.toString(); + } + + const execution = ResponseHelper.flattenExecutionData(fullExecutionData); + + const executionResult = await Db.collections.Execution!.save(execution as IExecutionFlattedDb); + executionId = typeof executionResult.id === "object" ? executionResult.id!.toString() : executionResult.id + ""; + } else { + // Is an existing execution we want to finish so update in DB + + const execution = { + id: executionId, + waitTill: null, + }; + + // @ts-ignore + await Db.collections.Execution!.update(executionId, execution); } - if (executionData.workflowData.id !== undefined && WorkflowHelpers.isWorkflowIdValid(executionData.workflowData.id.toString()) === true) { - fullExecutionData.workflowId = executionData.workflowData.id.toString(); - } - - const execution = ResponseHelper.flattenExecutionData(fullExecutionData); - - // Save the Execution in DB - const executionResult = await Db.collections.Execution!.save(execution as IExecutionFlattedDb); - - const executionId = typeof executionResult.id === "object" ? executionResult.id!.toString() : executionResult.id + ""; - this.activeExecutions[executionId] = { executionData, process, diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index ee48be8dd7..211af6fa1a 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -209,7 +209,7 @@ export class ActiveWorkflowRunner { return new Promise((resolve, reject) => { const executionMode = 'webhook'; //@ts-ignore - WebhookHelpers.executeWebhook(workflow, webhookData, workflowData, workflowStartNode, executionMode, undefined, req, res, (error: Error | null, data: object) => { + WebhookHelpers.executeWebhook(workflow, webhookData, workflowData, workflowStartNode, executionMode, undefined, undefined, undefined, req, res, (error: Error | null, data: object) => { if (error !== null) { return reject(error); } @@ -282,7 +282,7 @@ export class ActiveWorkflowRunner { * @memberof ActiveWorkflowRunner */ async addWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflowExecuteAdditionalDataWorkflow, mode: WorkflowExecuteMode, activation: WorkflowActivateMode): Promise { - const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData); + const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData, undefined, true); let path = '' as string | undefined; for (const webhookData of webhooks) { @@ -368,7 +368,7 @@ export class ActiveWorkflowRunner { const additionalData = await WorkflowExecuteAdditionalData.getBase(); - const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData); + const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData, undefined, true); for (const webhookData of webhooks) { await workflow.runWebhookMethod('delete', webhookData, NodeExecuteFunctions, mode, 'update', false); diff --git a/packages/cli/src/CredentialsHelper.ts b/packages/cli/src/CredentialsHelper.ts index f3427831df..fab915f73e 100644 --- a/packages/cli/src/CredentialsHelper.ts +++ b/packages/cli/src/CredentialsHelper.ts @@ -143,7 +143,7 @@ export class CredentialsHelper extends ICredentialsHelper { if (expressionResolveValues) { try { const workflow = new Workflow({ nodes: Object.values(expressionResolveValues.workflow.nodes), connections: expressionResolveValues.workflow.connectionsBySourceNode, active: false, nodeTypes: expressionResolveValues.workflow.nodeTypes }); - decryptedData = workflow.expression.getParameterValue(decryptedData as INodeParameters, expressionResolveValues.runExecutionData, expressionResolveValues.runIndex, expressionResolveValues.itemIndex, expressionResolveValues.node.name, expressionResolveValues.connectionInputData, mode, false, decryptedData) as ICredentialDataDecryptedObject; + decryptedData = workflow.expression.getParameterValue(decryptedData as INodeParameters, expressionResolveValues.runExecutionData, expressionResolveValues.runIndex, expressionResolveValues.itemIndex, expressionResolveValues.node.name, expressionResolveValues.connectionInputData, mode, {}, false, decryptedData) as ICredentialDataDecryptedObject; } catch (e) { e.message += ' [Error resolving credentials]'; throw e; @@ -160,7 +160,7 @@ export class CredentialsHelper extends ICredentialsHelper { const workflow = new Workflow({ nodes: [node!], connections: {}, active: false, nodeTypes: mockNodeTypes }); // Resolve expressions if any are set - decryptedData = workflow.expression.getComplexParameterValue(node!, decryptedData as INodeParameters, mode, undefined, decryptedData) as ICredentialDataDecryptedObject; + decryptedData = workflow.expression.getComplexParameterValue(node!, decryptedData as INodeParameters, mode, {}, undefined, decryptedData) as ICredentialDataDecryptedObject; } // Load and apply the credentials overwrites if any exist diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index e55f77e8e6..5ee6a48b7e 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -150,6 +150,7 @@ export interface IExecutionBase { // Data in regular format with references export interface IExecutionDb extends IExecutionBase { data: IRunExecutionData; + waitTill?: Date; workflowData?: IWorkflowBase; } @@ -163,6 +164,7 @@ export interface IExecutionResponse extends IExecutionBase { data: IRunExecutionData; retryOf?: string; retrySuccessId?: string; + waitTill?: Date; workflowData: IWorkflowBase; } @@ -176,6 +178,7 @@ export interface IExecutionFlatted extends IExecutionBase { export interface IExecutionFlattedDb extends IExecutionBase { id: number | string; data: string; + waitTill?: Date | null; workflowData: IWorkflowBase; } @@ -204,6 +207,7 @@ export interface IExecutionsSummary { mode: WorkflowExecuteMode; retryOf?: string; retrySuccessId?: string; + waitTill?: Date; startedAt: Date; stoppedAt?: Date; workflowId: string; diff --git a/packages/cli/src/ResponseHelper.ts b/packages/cli/src/ResponseHelper.ts index 24a9d37b53..bb447a91ba 100644 --- a/packages/cli/src/ResponseHelper.ts +++ b/packages/cli/src/ResponseHelper.ts @@ -163,6 +163,7 @@ export function flattenExecutionData(fullExecutionData: IExecutionDb): IExecutio const returnData: IExecutionFlatted = Object.assign({}, { data: stringify(fullExecutionData.data), mode: fullExecutionData.mode, + waitTill: fullExecutionData.waitTill, startedAt: fullExecutionData.startedAt, stoppedAt: fullExecutionData.stoppedAt, finished: fullExecutionData.finished ? fullExecutionData.finished : false, @@ -200,6 +201,7 @@ export function unflattenExecutionData(fullExecutionData: IExecutionFlattedDb): workflowData: fullExecutionData.workflowData as IWorkflowDb, data: parse(fullExecutionData.data), mode: fullExecutionData.mode, + waitTill: fullExecutionData.waitTill ? fullExecutionData.waitTill : undefined, startedAt: fullExecutionData.startedAt, stoppedAt: fullExecutionData.stoppedAt, finished: fullExecutionData.finished ? fullExecutionData.finished : false, diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 36ac50bbaa..f180c4b469 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -64,6 +64,9 @@ import { Push, ResponseHelper, TestWebhooks, + WaitingWebhooks, + WaitTracker, + WaitTrackerClass, WebhookHelpers, WebhookServer, WorkflowExecuteAdditionalData, @@ -96,6 +99,7 @@ import { import { FindManyOptions, FindOneOptions, + IsNull, LessThanOrEqual, Not, } from 'typeorm'; @@ -124,9 +128,11 @@ class App { activeWorkflowRunner: ActiveWorkflowRunner.ActiveWorkflowRunner; testWebhooks: TestWebhooks.TestWebhooks; endpointWebhook: string; + endpointWebhookWaiting: string; endpointWebhookTest: string; endpointPresetCredentials: string; externalHooks: IExternalHooksClass; + waitTracker: WaitTrackerClass; defaultWorkflowName: string; saveDataErrorExecution: string; saveDataSuccessExecution: string; @@ -150,6 +156,7 @@ class App { this.app = express(); this.endpointWebhook = config.get('endpoints.webhook') as string; + this.endpointWebhookWaiting = config.get('endpoints.webhookWaiting') as string; this.endpointWebhookTest = config.get('endpoints.webhookTest') as string; this.defaultWorkflowName = config.get('workflows.defaultName') as string; @@ -168,6 +175,7 @@ class App { this.push = Push.getInstance(); this.activeExecutionsInstance = ActiveExecutions.getInstance(); + this.waitTracker = WaitTracker(); this.protocol = config.get('protocol'); this.sslKey = config.get('ssl_key'); @@ -620,7 +628,6 @@ class App { return { name: `${nameToReturn} ${maxSuffix + 1}` }; })); - // Returns a specific workflow this.app.get(`/${this.restEndpoint}/workflows/:id`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise => { const workflow = await Db.collections.Workflow!.findOne(req.params.id, { relations: ['tags'] }); @@ -1621,6 +1628,9 @@ class App { executingWorkflowIds.push(...this.activeExecutionsInstance.getActiveExecutions().map(execution => execution.id.toString()) as string[]); const countFilter = JSON.parse(JSON.stringify(filter)); + if (countFilter.waitTill !== undefined) { + countFilter.waitTill = Not(IsNull()); + } countFilter.id = Not(In(executingWorkflowIds)); const resultsQuery = await Db.collections.Execution! @@ -1631,6 +1641,7 @@ class App { 'execution.mode', 'execution.retryOf', 'execution.retrySuccessId', + 'execution.waitTill', 'execution.startedAt', 'execution.stoppedAt', 'execution.workflowData', @@ -1639,7 +1650,14 @@ class App { .take(limit); Object.keys(filter).forEach((filterField) => { - resultsQuery.andWhere(`execution.${filterField} = :${filterField}`, {[filterField]: filter[filterField]}); + if (filterField === 'waitTill') { + resultsQuery.andWhere(`execution.${filterField} is not null`); + } else if(filterField === 'finished' && filter[filterField] === false) { + resultsQuery.andWhere(`execution.${filterField} = :${filterField}`, {[filterField]: filter[filterField]}); + resultsQuery.andWhere(`execution.waitTill is null`); + } else { + resultsQuery.andWhere(`execution.${filterField} = :${filterField}`, {[filterField]: filter[filterField]}); + } }); if (req.query.lastId) { resultsQuery.andWhere(`execution.id < :lastId`, {lastId: req.query.lastId}); @@ -1667,6 +1685,7 @@ class App { mode: result.mode, retryOf: result.retryOf ? result.retryOf.toString() : undefined, retrySuccessId: result.retrySuccessId ? result.retrySuccessId.toString() : undefined, + waitTill: result.waitTill as Date | undefined, startedAt: result.startedAt, stoppedAt: result.stoppedAt, workflowId: result.workflowData!.id ? result.workflowData!.id!.toString() : '', @@ -1893,15 +1912,22 @@ class App { // Manual executions should still be stoppable, so // try notifying the `activeExecutions` to stop it. const result = await this.activeExecutionsInstance.stopExecution(req.params.id); - if (result !== undefined) { - const returnData: IExecutionsStopData = { + + if (result === undefined) { + // If active execution could not be found check if it is a waiting one + try { + return await this.waitTracker.stopExecution(req.params.id); + } catch (error) { + // Ignore, if it errors as then it is probably a currently running + // execution + } + } else { + return { mode: result.mode, startedAt: new Date(result.startedAt), - stoppedAt: result.stoppedAt ? new Date(result.stoppedAt) : undefined, + stoppedAt: result.stoppedAt ? new Date(result.stoppedAt) : undefined, finished: result.finished, - }; - - return returnData; + } as IExecutionsStopData; } const currentJobs = await Queue.getInstance().getJobs(['active', 'waiting']); @@ -1932,17 +1958,19 @@ class App { // Stopt he execution and wait till it is done and we got the data const result = await this.activeExecutionsInstance.stopExecution(executionId); + let returnData: IExecutionsStopData; if (result === undefined) { - throw new Error(`The execution id "${executionId}" could not be found.`); + // If active execution could not be found check if it is a waiting one + returnData = await this.waitTracker.stopExecution(executionId); + } else { + returnData = { + mode: result.mode, + startedAt: new Date(result.startedAt), + stoppedAt: result.stoppedAt ? new Date(result.stoppedAt) : undefined, + finished: result.finished, + }; } - const returnData: IExecutionsStopData = { - mode: result.mode, - startedAt: new Date(result.startedAt), - stoppedAt: result.stoppedAt ? new Date(result.stoppedAt) : undefined, - finished: result.finished, - }; - return returnData; } })); @@ -1988,6 +2016,76 @@ class App { WebhookServer.registerProductionWebhooks.apply(this); } + // ---------------------------------------- + // Waiting Webhooks + // ---------------------------------------- + + const waitingWebhooks = new WaitingWebhooks(); + + // HEAD webhook-waiting requests + this.app.head(`/${this.endpointWebhookWaiting}/*`, async (req: express.Request, res: express.Response) => { + // Cut away the "/webhook-waiting/" to get the registred part of the url + const requestUrl = (req as ICustomRequest).parsedUrl!.pathname!.slice(this.endpointWebhookWaiting.length + 2); + + let response; + try { + response = await waitingWebhooks.executeWebhook('HEAD', requestUrl, req, res); + } catch (error) { + ResponseHelper.sendErrorResponse(res, error); + return; + } + + if (response.noWebhookResponse === true) { + // Nothing else to do as the response got already sent + return; + } + + ResponseHelper.sendSuccessResponse(res, response.data, true, response.responseCode); + }); + + // GET webhook-waiting requests + this.app.get(`/${this.endpointWebhookWaiting}/*`, async (req: express.Request, res: express.Response) => { + // Cut away the "/webhook-waiting/" to get the registred part of the url + const requestUrl = (req as ICustomRequest).parsedUrl!.pathname!.slice(this.endpointWebhookWaiting.length + 2); + + let response; + try { + response = await waitingWebhooks.executeWebhook('GET', requestUrl, req, res); + } catch (error) { + ResponseHelper.sendErrorResponse(res, error); + return; + } + + if (response.noWebhookResponse === true) { + // Nothing else to do as the response got already sent + return; + } + + ResponseHelper.sendSuccessResponse(res, response.data, true, response.responseCode); + }); + + // POST webhook-waiting requests + this.app.post(`/${this.endpointWebhookWaiting}/*`, async (req: express.Request, res: express.Response) => { + // Cut away the "/webhook-waiting/" to get the registred part of the url + const requestUrl = (req as ICustomRequest).parsedUrl!.pathname!.slice(this.endpointWebhookWaiting.length + 2); + + let response; + try { + response = await waitingWebhooks.executeWebhook('POST', requestUrl, req, res); + } catch (error) { + ResponseHelper.sendErrorResponse(res, error); + return; + } + + if (response.noWebhookResponse === true) { + // Nothing else to do as the response got already sent + return; + } + + ResponseHelper.sendSuccessResponse(res, response.data, true, response.responseCode); + }); + + // HEAD webhook requests (test for UI) this.app.head(`/${this.endpointWebhookTest}/*`, async (req: express.Request, res: express.Response) => { // Cut away the "/webhook-test/" to get the registred part of the url diff --git a/packages/cli/src/TestWebhooks.ts b/packages/cli/src/TestWebhooks.ts index a8aa17720f..96e6f299a5 100644 --- a/packages/cli/src/TestWebhooks.ts +++ b/packages/cli/src/TestWebhooks.ts @@ -105,7 +105,7 @@ export class TestWebhooks { return new Promise(async (resolve, reject) => { try { const executionMode = 'manual'; - const executionId = await WebhookHelpers.executeWebhook(workflow, webhookData!, this.testWebhookData[webhookKey].workflowData, workflowStartNode, executionMode, this.testWebhookData[webhookKey].sessionId, request, response, (error: Error | null, data: IResponseCallbackData) => { + const executionId = await WebhookHelpers.executeWebhook(workflow, webhookData!, this.testWebhookData[webhookKey].workflowData, workflowStartNode, executionMode, this.testWebhookData[webhookKey].sessionId, undefined, undefined, request, response, (error: Error | null, data: IResponseCallbackData) => { if (error !== null) { return reject(error); } @@ -163,10 +163,9 @@ export class TestWebhooks { * @memberof TestWebhooks */ async needsWebhookData(workflowData: IWorkflowDb, workflow: Workflow, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, activation: WorkflowActivateMode, sessionId?: string, destinationNode?: string): Promise { - const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData, destinationNode); - - if (webhooks.length === 0) { - // No Webhooks found + const webhooks = WebhookHelpers.getWorkflowWebhooks(workflow, additionalData, destinationNode, true); + if (!webhooks.find(webhook => webhook.webhookDescription.restartWebhook !== true)) { + // No webhooks found to start a workflow return false; } diff --git a/packages/cli/src/WaitTracker.ts b/packages/cli/src/WaitTracker.ts new file mode 100644 index 0000000000..81ee39e418 --- /dev/null +++ b/packages/cli/src/WaitTracker.ts @@ -0,0 +1,181 @@ +import { + ActiveExecutions, + DatabaseType, + Db, + GenericHelpers, + IExecutionFlattedDb, + IExecutionsStopData, + IWorkflowExecutionDataProcess, + ResponseHelper, + WorkflowCredentials, + WorkflowRunner, +} from '.'; + +import { + IRun, + LoggerProxy as Logger, + WorkflowOperationError, +} from 'n8n-workflow'; + +import { + FindManyOptions, + LessThanOrEqual, + ObjectLiteral, +} from 'typeorm'; + +import { DateUtils } from 'typeorm/util/DateUtils'; + + +export class WaitTrackerClass { + activeExecutionsInstance: ActiveExecutions.ActiveExecutions; + + private waitingExecutions: { + [key: string]: { + executionId: string, + timer: NodeJS.Timeout, + }; + } = {}; + + mainTimer: NodeJS.Timeout; + + + constructor() { + this.activeExecutionsInstance = ActiveExecutions.getInstance(); + + // Poll every 60 seconds a list of upcoming executions + this.mainTimer = setInterval(() => { + this.getwaitingExecutions(); + }, 60000); + + this.getwaitingExecutions(); + } + + + async getwaitingExecutions() { + Logger.debug('Wait tracker querying database for waiting executions'); + // Find all the executions which should be triggered in the next 70 seconds + const findQuery: FindManyOptions = { + select: ['id', 'waitTill'], + where: { + waitTill: LessThanOrEqual(new Date(Date.now() + 70000)), + }, + order: { + waitTill: 'ASC', + }, + }; + const dbType = await GenericHelpers.getConfigValue('database.type') as DatabaseType; + if (dbType === 'sqlite') { + // This is needed because of issue in TypeORM <> SQLite: + // https://github.com/typeorm/typeorm/issues/2286 + (findQuery.where! as ObjectLiteral).waitTill = LessThanOrEqual(DateUtils.mixedDateToUtcDatetimeString(new Date(Date.now() + 70000))); + } + + const executions = await Db.collections.Execution!.find(findQuery); + + if (executions.length === 0) { + return; + } + + const executionIds = executions.map(execution => execution.id.toString()).join(', '); + Logger.debug(`Wait tracker found ${executions.length} executions. Setting timer for IDs: ${executionIds}`); + + // Add timers for each waiting execution that they get started at the correct time + for (const execution of executions) { + const executionId = execution.id.toString(); + if (this.waitingExecutions[executionId] === undefined) { + const triggerTime = execution.waitTill!.getTime() - new Date().getTime(); + this.waitingExecutions[executionId] = { + executionId, + timer: setTimeout(() => { + this.startExecution(executionId); + }, triggerTime), + }; + } + } + } + + + async stopExecution(executionId: string): Promise { + if (this.waitingExecutions[executionId] !== undefined) { + // The waiting execution was already sheduled to execute. + // So stop timer and remove. + clearTimeout(this.waitingExecutions[executionId].timer); + delete this.waitingExecutions[executionId]; + } + + // Also check in database + const execution = await Db.collections.Execution!.findOne(executionId); + + if (execution === undefined || !execution.waitTill) { + throw new Error(`The execution ID "${executionId}" could not be found.`); + } + + const fullExecutionData = ResponseHelper.unflattenExecutionData(execution); + + // Set in execution in DB as failed and remove waitTill time + const error = new WorkflowOperationError('Workflow-Execution has been canceled!'); + + fullExecutionData.data.resultData.error = { + ...error, + message: error.message, + stack: error.stack, + }; + + fullExecutionData.stoppedAt = new Date(); + fullExecutionData.waitTill = undefined; + + await Db.collections.Execution!.update(executionId, ResponseHelper.flattenExecutionData(fullExecutionData)); + + return { + mode: fullExecutionData.mode, + startedAt: new Date(fullExecutionData.startedAt), + stoppedAt: fullExecutionData.stoppedAt ? new Date(fullExecutionData.stoppedAt) : undefined, + finished: fullExecutionData.finished, + }; + } + + + startExecution(executionId: string) { + Logger.debug(`Wait tracker resuming execution ${executionId}`, {executionId}); + delete this.waitingExecutions[executionId]; + + (async () => { + // Get the data to execute + const fullExecutionDataFlatted = await Db.collections.Execution!.findOne(executionId); + + if (fullExecutionDataFlatted === undefined) { + throw new Error(`The execution with the id "${executionId}" does not exist.`); + } + + const fullExecutionData = ResponseHelper.unflattenExecutionData(fullExecutionDataFlatted); + + if (fullExecutionData.finished === true) { + throw new Error('The execution did succeed and can so not be started again.'); + } + + const data: IWorkflowExecutionDataProcess = { + executionMode: fullExecutionData.mode, + executionData: fullExecutionData.data, + workflowData: fullExecutionData.workflowData, + }; + + // Start the execution again + const workflowRunner = new WorkflowRunner(); + await workflowRunner.run(data, false, false, executionId); + })().catch((error) => { + Logger.error(`There was a problem starting the waiting execution with id "${executionId}": "${error.message}"`, { executionId }); + }); + + } +} + + +let waitTrackerInstance: WaitTrackerClass | undefined; + +export function WaitTracker(): WaitTrackerClass { + if (waitTrackerInstance === undefined) { + waitTrackerInstance = new WaitTrackerClass(); + } + + return waitTrackerInstance; +} diff --git a/packages/cli/src/WaitingWebhooks.ts b/packages/cli/src/WaitingWebhooks.ts new file mode 100644 index 0000000000..f0b84d3804 --- /dev/null +++ b/packages/cli/src/WaitingWebhooks.ts @@ -0,0 +1,117 @@ +import { + Db, + IExecutionResponse, + IResponseCallbackData, + IWorkflowDb, + NodeTypes, + ResponseHelper, + WebhookHelpers, + WorkflowCredentials, + WorkflowExecuteAdditionalData, +} from '.'; + +import { + INode, + IRunExecutionData, + NodeHelpers, + WebhookHttpMethod, + Workflow, +} from 'n8n-workflow'; + +import * as express from 'express'; +import { + LoggerProxy as Logger, +} from 'n8n-workflow'; + +export class WaitingWebhooks { + + async executeWebhook(httpMethod: WebhookHttpMethod, fullPath: string, req: express.Request, res: express.Response): Promise { + Logger.debug(`Received waiting-webhoook "${httpMethod}" for path "${fullPath}"`); + + // Reset request parameters + req.params = {}; + + // Remove trailing slash + if (fullPath.endsWith('/')) { + fullPath = fullPath.slice(0, -1); + } + + const pathParts = fullPath.split('/'); + + const executionId = pathParts.shift(); + const path = pathParts.join('/'); + + const execution = await Db.collections.Execution?.findOne(executionId); + + if (execution === undefined) { + throw new ResponseHelper.ResponseError(`The execution "${executionId} does not exist.`, 404, 404); + } + + const fullExecutionData = ResponseHelper.unflattenExecutionData(execution); + + if (fullExecutionData.finished === true || fullExecutionData.data.resultData.error) { + throw new ResponseHelper.ResponseError(`The execution "${executionId} has finished already.`, 409, 409); + } + + return this.startExecution(httpMethod, path, fullExecutionData, req, res); + } + + + async startExecution(httpMethod: WebhookHttpMethod, path: string, fullExecutionData: IExecutionResponse, req: express.Request, res: express.Response): Promise { + const executionId = fullExecutionData.id; + + if (fullExecutionData.finished === true) { + throw new Error('The execution did succeed and can so not be started again.'); + } + + const lastNodeExecuted = fullExecutionData!.data.resultData.lastNodeExecuted as string; + + // Set the node as disabled so that the data does not get executed again as it would result + // in starting the wait all over again + fullExecutionData!.data.executionData!.nodeExecutionStack[0].node.disabled = true; + + // Remove waitTill information else the execution would stop + fullExecutionData!.data.waitTill = undefined; + + // Remove the data of the node execution again else it will display the node as executed twice + fullExecutionData!.data.resultData.runData[lastNodeExecuted].pop(); + + const workflowData = fullExecutionData.workflowData; + + const nodeTypes = NodeTypes(); + const workflow = new Workflow({ id: workflowData.id!.toString(), name: workflowData.name, nodes: workflowData.nodes, connections: workflowData.connections, active: workflowData.active, nodeTypes, staticData: workflowData.staticData, settings: workflowData.settings }); + + const additionalData = await WorkflowExecuteAdditionalData.getBase(); + + const webhookData = NodeHelpers.getNodeWebhooks(workflow, workflow.getNode(lastNodeExecuted) as INode, additionalData).filter((webhook) => { + return (webhook.httpMethod === httpMethod && webhook.path === path && webhook.webhookDescription.restartWebhook === true); + })[0]; + + if (webhookData === undefined) { + // If no data got found it means that the execution can not be started via a webhook. + // Return 404 because we do not want to give any data if the execution exists or not. + const errorMessage = `The execution "${executionId}" with webhook suffix path "${path}" is not known.`; + throw new ResponseHelper.ResponseError(errorMessage, 404, 404); + } + + const workflowStartNode = workflow.getNode(lastNodeExecuted); + + if (workflowStartNode === null) { + throw new ResponseHelper.ResponseError('Could not find node to process webhook.', 404, 404); + } + + const runExecutionData = fullExecutionData.data as IRunExecutionData; + + return new Promise((resolve, reject) => { + const executionMode = 'webhook'; + WebhookHelpers.executeWebhook(workflow, webhookData, workflowData as IWorkflowDb, workflowStartNode, executionMode, undefined, runExecutionData, fullExecutionData.id, req, res, (error: Error | null, data: object) => { + if (error !== null) { + return reject(error); + } + resolve(data); + }); + }); + + } + +} diff --git a/packages/cli/src/WebhookHelpers.ts b/packages/cli/src/WebhookHelpers.ts index a88572d3ac..6005f7740d 100644 --- a/packages/cli/src/WebhookHelpers.ts +++ b/packages/cli/src/WebhookHelpers.ts @@ -3,7 +3,6 @@ import { get } from 'lodash'; import { ActiveExecutions, - ExternalHooks, GenericHelpers, IExecutionDb, IResponseCallbackData, @@ -29,6 +28,7 @@ import { IRunExecutionData, IWebhookData, IWebhookResponseData, + IWorkflowDataProxyAdditionalKeys, IWorkflowExecuteAdditionalData, LoggerProxy as Logger, NodeHelpers, @@ -47,7 +47,7 @@ const activeExecutions = ActiveExecutions.getInstance(); * @param {Workflow} workflow * @returns {IWebhookData[]} */ -export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflowExecuteAdditionalData, destinationNode?: string): IWebhookData[] { +export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflowExecuteAdditionalData, destinationNode?: string, ignoreRestartWehbooks = false): IWebhookData[] { // Check all the nodes in the workflow if they have webhooks const returnData: IWebhookData[] = []; @@ -65,7 +65,7 @@ export function getWorkflowWebhooks(workflow: Workflow, additionalData: IWorkflo // and no other ones continue; } - returnData.push.apply(returnData, NodeHelpers.getNodeWebhooks(workflow, node, additionalData)); + returnData.push.apply(returnData, NodeHelpers.getNodeWebhooks(workflow, node, additionalData, ignoreRestartWehbooks)); } return returnData; @@ -106,7 +106,7 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { * @param {((error: Error | null, data: IResponseCallbackData) => void)} responseCallback * @returns {(Promise)} */ - export async function executeWebhook(workflow: Workflow, webhookData: IWebhookData, workflowData: IWorkflowDb, workflowStartNode: INode, executionMode: WorkflowExecuteMode, sessionId: string | undefined, req: express.Request, res: express.Response, responseCallback: (error: Error | null, data: IResponseCallbackData) => void): Promise { +export async function executeWebhook(workflow: Workflow, webhookData: IWebhookData, workflowData: IWorkflowDb, workflowStartNode: INode, executionMode: WorkflowExecuteMode, sessionId: string | undefined, runExecutionData: IRunExecutionData | undefined, executionId: string | undefined, req: express.Request, res: express.Response, responseCallback: (error: Error | null, data: IResponseCallbackData) => void): Promise { // Get the nodeType to know which responseMode is set const nodeType = workflow.nodeTypes.getByName(workflowStartNode.type); if (nodeType === undefined) { @@ -115,9 +115,13 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { throw new ResponseHelper.ResponseError(errorMessage, 500, 500); } + const additionalKeys: IWorkflowDataProxyAdditionalKeys = { + $executionId: executionId, + }; + // Get the responseMode - const responseMode = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseMode'], executionMode, 'onReceived'); - const responseCode = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseCode'], executionMode, 200) as number; + const responseMode = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseMode'], executionMode, additionalKeys, 'onReceived'); + const responseCode = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseCode'], executionMode, additionalKeys, 200) as number; if (!['onReceived', 'lastNode'].includes(responseMode as string)) { // If the mode is not known we error. Is probably best like that instead of using @@ -174,8 +178,12 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { // Save static data if it changed await WorkflowHelpers.saveStaticData(workflow); + const additionalKeys: IWorkflowDataProxyAdditionalKeys = { + $executionId: executionId, + }; + if (webhookData.webhookDescription['responseHeaders'] !== undefined) { - const responseHeaders = workflow.expression.getComplexParameterValue(workflowStartNode, webhookData.webhookDescription['responseHeaders'], executionMode, undefined) as { + const responseHeaders = workflow.expression.getComplexParameterValue(workflowStartNode, webhookData.webhookDescription['responseHeaders'], executionMode, additionalKeys, undefined) as { entries?: Array<{ name: string; value: string; @@ -256,7 +264,7 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { } ); - const runExecutionData: IRunExecutionData = { + runExecutionData = runExecutionData || { startData: { }, resultData: { @@ -267,7 +275,13 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { nodeExecutionStack, waitingExecution: {}, }, - }; + } as IRunExecutionData; + + if (executionId !== undefined) { + // Set the data the webhook node did return on the waiting node if executionId + // already exists as it means that we are restarting an existing execution. + runExecutionData.executionData!.nodeExecutionStack[0].data.main = webhookResultData.workflowData; + } if (Object.keys(runExecutionDataMerge).length !== 0) { // If data to merge got defined add it to the execution data @@ -283,7 +297,7 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { // Start now to run the workflow const workflowRunner = new WorkflowRunner(); - const executionId = await workflowRunner.run(runData, true, !didSendResponse); + executionId = await workflowRunner.run(runData, true, !didSendResponse, executionId); Logger.verbose(`Started execution of workflow "${workflow.name}" from webhook with execution ID ${executionId}`, { executionId }); @@ -330,7 +344,11 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { return data; } - const responseData = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseData'], executionMode, 'firstEntryJson'); + const additionalKeys: IWorkflowDataProxyAdditionalKeys = { + $executionId: executionId, + }; + + const responseData = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseData'], executionMode, additionalKeys, 'firstEntryJson'); if (didSendResponse === false) { let data: IDataObject | IDataObject[]; @@ -345,13 +363,13 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { data = returnData.data!.main[0]![0].json; - const responsePropertyName = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responsePropertyName'], executionMode, undefined); + const responsePropertyName = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responsePropertyName'], executionMode, additionalKeys, undefined); if (responsePropertyName !== undefined) { data = get(data, responsePropertyName as string) as IDataObject; } - const responseContentType = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseContentType'], executionMode, undefined); + const responseContentType = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseContentType'], executionMode, additionalKeys, undefined); if (responseContentType !== undefined) { // Send the webhook response manually to be able to set the content-type @@ -384,7 +402,7 @@ export function getWorkflowWebhooksBasic(workflow: Workflow): IWebhookData[] { didSendResponse = true; } - const responseBinaryPropertyName = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseBinaryPropertyName'], executionMode, 'data'); + const responseBinaryPropertyName = workflow.expression.getSimpleParameterValue(workflowStartNode, webhookData.webhookDescription['responseBinaryPropertyName'], executionMode, additionalKeys, 'data'); if (responseBinaryPropertyName === undefined && didSendResponse === false) { responseCallback(new Error('No "responseBinaryPropertyName" is set.'), {}); diff --git a/packages/cli/src/WebhookServer.ts b/packages/cli/src/WebhookServer.ts index 245e3a2504..83c28ab2d0 100644 --- a/packages/cli/src/WebhookServer.ts +++ b/packages/cli/src/WebhookServer.ts @@ -26,6 +26,11 @@ import * as config from '../config'; import * as parseUrl from 'parseurl'; export function registerProductionWebhooks() { + + // ---------------------------------------- + // Regular Webhooks + // ---------------------------------------- + // HEAD webhook requests this.app.head(`/${this.endpointWebhook}/*`, async (req: express.Request, res: express.Response) => { // Cut away the "/webhook/" to get the registred part of the url diff --git a/packages/cli/src/WorkflowExecuteAdditionalData.ts b/packages/cli/src/WorkflowExecuteAdditionalData.ts index 8a55fcdb08..cc25661354 100644 --- a/packages/cli/src/WorkflowExecuteAdditionalData.ts +++ b/packages/cli/src/WorkflowExecuteAdditionalData.ts @@ -256,7 +256,7 @@ export function hookFunctionsPreExecute(parentProcessMode?: string): IWorkflowEx if (execution === undefined) { // Something went badly wrong if this happens. // This check is here mostly to make typescript happy. - return undefined; + return; } const fullExecutionData: IExecutionResponse = ResponseHelper.unflattenExecutionData(execution); @@ -267,11 +267,9 @@ export function hookFunctionsPreExecute(parentProcessMode?: string): IWorkflowEx return; } - if (fullExecutionData.data === undefined) { fullExecutionData.data = { - startData: { - }, + startData: {}, resultData: { runData: {}, }, @@ -351,7 +349,7 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks { saveManualExecutions = this.workflowData.settings.saveManualExecutions as boolean; } - if (isManualMode && saveManualExecutions === false) { + if (isManualMode && saveManualExecutions === false && !fullRunData.waitTill) { // Data is always saved, so we remove from database await Db.collections.Execution!.delete(this.executionId); return; @@ -369,12 +367,14 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks { if (workflowDidSucceed === true && saveDataSuccessExecution === 'none' || workflowDidSucceed === false && saveDataErrorExecution === 'none' ) { - if (!isManualMode) { - executeErrorWorkflow(this.workflowData, fullRunData, this.mode, undefined, this.retryOf); + if (!fullRunData.waitTill) { + if (!isManualMode) { + executeErrorWorkflow(this.workflowData, fullRunData, this.mode, undefined, this.retryOf); + } + // Data is always saved, so we remove from database + await Db.collections.Execution!.delete(this.executionId); + return; } - // Data is always saved, so we remove from database - await Db.collections.Execution!.delete(this.executionId); - return; } const fullExecutionData: IExecutionDb = { @@ -384,6 +384,7 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks { startedAt: fullRunData.startedAt, stoppedAt: fullRunData.stoppedAt, workflowData: this.workflowData, + waitTill: fullRunData.waitTill, }; if (this.retryOf !== undefined) { @@ -469,6 +470,7 @@ function hookFunctionsSaveWorker(): IWorkflowExecuteHooks { startedAt: fullRunData.startedAt, stoppedAt: fullRunData.stoppedAt, workflowData: this.workflowData, + waitTill: fullRunData.data.waitTill, }; if (this.retryOf !== undefined) { @@ -731,6 +733,7 @@ export async function getBase(currentNodeParameters?: INodeParameters, execution const timezone = config.get('generic.timezone') as string; const webhookBaseUrl = urlBaseWebhook + config.get('endpoints.webhook') as string; + const webhookWaitingBaseUrl = urlBaseWebhook + config.get('endpoints.webhookWaiting') as string; const webhookTestBaseUrl = urlBaseWebhook + config.get('endpoints.webhookTest') as string; const encryptionKey = await UserSettings.getEncryptionKey(); @@ -745,6 +748,7 @@ export async function getBase(currentNodeParameters?: INodeParameters, execution restApiUrl: urlBaseWebhook + config.get('endpoints.rest') as string, timezone, webhookBaseUrl, + webhookWaitingBaseUrl, webhookTestBaseUrl, currentNodeParameters, executionTimeoutTimestamp, diff --git a/packages/cli/src/WorkflowRunner.ts b/packages/cli/src/WorkflowRunner.ts index 564d01a975..9a8c66430f 100644 --- a/packages/cli/src/WorkflowRunner.ts +++ b/packages/cli/src/WorkflowRunner.ts @@ -123,19 +123,18 @@ export class WorkflowRunner { * @returns {Promise} * @memberof WorkflowRunner */ - async run(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean, realtime?: boolean): Promise { + async run(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean, realtime?: boolean, executionId?: string): Promise { const executionsProcess = config.get('executions.process') as string; const executionsMode = config.get('executions.mode') as string; - let executionId: string; if (executionsMode === 'queue' && data.executionMode !== 'manual') { // Do not run "manual" executions in bull because sending events to the // frontend would not be possible - executionId = await this.runBull(data, loadStaticData, realtime); + executionId = await this.runBull(data, loadStaticData, realtime, executionId); } else if (executionsProcess === 'main') { - executionId = await this.runMainProcess(data, loadStaticData); + executionId = await this.runMainProcess(data, loadStaticData, executionId); } else { - executionId = await this.runSubprocess(data, loadStaticData); + executionId = await this.runSubprocess(data, loadStaticData, executionId); } const externalHooks = ExternalHooks(); @@ -162,7 +161,7 @@ export class WorkflowRunner { * @returns {Promise} * @memberof WorkflowRunner */ - async runMainProcess(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean): Promise { + async runMainProcess(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean, restartExecutionId?: string): Promise { if (loadStaticData === true && data.workflowData.id) { data.workflowData.staticData = await WorkflowHelpers.getStaticDataById(data.workflowData.id as string); } @@ -186,7 +185,10 @@ export class WorkflowRunner { const additionalData = await WorkflowExecuteAdditionalData.getBase(undefined, workflowTimeout <= 0 ? undefined : Date.now() + workflowTimeout * 1000); // Register the active execution - const executionId = await this.activeExecutions.add(data, undefined); + const executionId = await this.activeExecutions.add(data, undefined, restartExecutionId) as string; + additionalData.executionId = executionId; + + Logger.verbose(`Execution for workflow ${data.workflowData.name} was assigned id ${executionId}`, {executionId}); let workflowExecution: PCancelable; try { @@ -240,12 +242,12 @@ export class WorkflowRunner { return executionId; } - async runBull(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean, realtime?: boolean): Promise { + async runBull(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean, realtime?: boolean, restartExecutionId?: string): Promise { // TODO: If "loadStaticData" is set to true it has to load data new on worker // Register the active execution - const executionId = await this.activeExecutions.add(data, undefined); + const executionId = await this.activeExecutions.add(data, undefined, restartExecutionId); const jobData: IBullJobData = { executionId, @@ -412,7 +414,7 @@ export class WorkflowRunner { * @returns {Promise} * @memberof WorkflowRunner */ - async runSubprocess(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean): Promise { + async runSubprocess(data: IWorkflowExecutionDataProcess, loadStaticData?: boolean, restartExecutionId?: string): Promise { let startedAt = new Date(); const subprocess = fork(pathJoin(__dirname, 'WorkflowRunnerProcess.js')); @@ -421,7 +423,7 @@ export class WorkflowRunner { } // Register the active execution - const executionId = await this.activeExecutions.add(data, subprocess); + const executionId = await this.activeExecutions.add(data, subprocess, restartExecutionId); // Supply all nodeTypes and credentialTypes const nodeTypeData = WorkflowHelpers.getAllNodeTypeData() as ITransferNodeTypes; diff --git a/packages/cli/src/WorkflowRunnerProcess.ts b/packages/cli/src/WorkflowRunnerProcess.ts index 715b8ada44..6b3262322b 100644 --- a/packages/cli/src/WorkflowRunnerProcess.ts +++ b/packages/cli/src/WorkflowRunnerProcess.ts @@ -150,6 +150,7 @@ export class WorkflowRunnerProcess { this.workflow = new Workflow({ id: this.data.workflowData.id as string | undefined, name: this.data.workflowData.name, nodes: this.data.workflowData!.nodes, connections: this.data.workflowData!.connections, active: this.data.workflowData!.active, nodeTypes, staticData: this.data.workflowData!.staticData, settings: this.data.workflowData!.settings }); const additionalData = await WorkflowExecuteAdditionalData.getBase(undefined, workflowTimeout <= 0 ? undefined : Date.now() + workflowTimeout * 1000); additionalData.hooks = this.getProcessForwardHooks(); + additionalData.executionId = inputData.executionId; additionalData.sendMessageToUI = async (source: string, message: any) => { // tslint:disable-line:no-any if (workflowRunner.data!.executionMode !== 'manual') { diff --git a/packages/cli/src/databases/entities/ExecutionEntity.ts b/packages/cli/src/databases/entities/ExecutionEntity.ts index b788f5e153..ba6b60807f 100644 --- a/packages/cli/src/databases/entities/ExecutionEntity.ts +++ b/packages/cli/src/databases/entities/ExecutionEntity.ts @@ -53,4 +53,8 @@ export class ExecutionEntity implements IExecutionFlattedDb { @Index() @Column({ nullable: true }) workflowId: string; + + @Index() + @Column({ type: resolveDataType('datetime') as ColumnOptions['type'], nullable: true }) + waitTill: Date; } diff --git a/packages/cli/src/databases/mysqldb/migrations/1626183952959-AddWaitColumn.ts b/packages/cli/src/databases/mysqldb/migrations/1626183952959-AddWaitColumn.ts new file mode 100644 index 0000000000..ee2aa560e1 --- /dev/null +++ b/packages/cli/src/databases/mysqldb/migrations/1626183952959-AddWaitColumn.ts @@ -0,0 +1,22 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; +import * as config from '../../../../config'; + +export class AddWaitColumnId1626183952959 implements MigrationInterface { + name = 'AddWaitColumnId1626183952959'; + + async up(queryRunner: QueryRunner): Promise { + const tablePrefix = config.get('database.tablePrefix'); + + await queryRunner.query('ALTER TABLE `' + tablePrefix + 'execution_entity` ADD `waitTill` DATETIME NULL'); + await queryRunner.query('CREATE INDEX `IDX_' + tablePrefix + 'ca4a71b47f28ac6ea88293a8e2` ON `' + tablePrefix + 'execution_entity` (`waitTill`)'); + } + + async down(queryRunner: QueryRunner): Promise { + const tablePrefix = config.get('database.tablePrefix'); + + await queryRunner.query( + 'DROP INDEX `IDX_' + tablePrefix + 'ca4a71b47f28ac6ea88293a8e2` ON `' + tablePrefix + 'execution_entity`' + ); + await queryRunner.query('ALTER TABLE `' + tablePrefix + 'execution_entity` DROP COLUMN `waitTill`'); + } +} diff --git a/packages/cli/src/databases/mysqldb/migrations/index.ts b/packages/cli/src/databases/mysqldb/migrations/index.ts index 1054d68cfc..b48bc58aff 100644 --- a/packages/cli/src/databases/mysqldb/migrations/index.ts +++ b/packages/cli/src/databases/mysqldb/migrations/index.ts @@ -8,6 +8,7 @@ import { ChangeCredentialDataSize1620729500000 } from './1620729500000-ChangeCre import { CreateTagEntity1617268711084 } from './1617268711084-CreateTagEntity'; import { UniqueWorkflowNames1620826335440 } from './1620826335440-UniqueWorkflowNames'; import { CertifyCorrectCollation1623936588000 } from './1623936588000-CertifyCorrectCollation'; +import { AddWaitColumnId1626183952959 } from './1626183952959-AddWaitColumn'; export const mysqlMigrations = [ InitialMigration1588157391238, @@ -20,4 +21,5 @@ export const mysqlMigrations = [ CreateTagEntity1617268711084, UniqueWorkflowNames1620826335440, CertifyCorrectCollation1623936588000, + AddWaitColumnId1626183952959, ]; diff --git a/packages/cli/src/databases/postgresdb/migrations/1626176912946-AddwaitTill.ts b/packages/cli/src/databases/postgresdb/migrations/1626176912946-AddwaitTill.ts new file mode 100644 index 0000000000..3bef043a83 --- /dev/null +++ b/packages/cli/src/databases/postgresdb/migrations/1626176912946-AddwaitTill.ts @@ -0,0 +1,31 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; +import * as config from '../../../../config'; + +export class AddwaitTill1626176912946 implements MigrationInterface { + name = 'AddwaitTill1626176912946'; + + async up(queryRunner: QueryRunner): Promise { + let tablePrefix = config.get('database.tablePrefix'); + const tablePrefixPure = tablePrefix; + const schema = config.get('database.postgresdb.schema'); + if (schema) { + tablePrefix = schema + '.' + tablePrefix; + } + + await queryRunner.query(`ALTER TABLE ${tablePrefix}execution_entity ADD "waitTill" TIMESTAMP`); + await queryRunner.query(`CREATE INDEX IF NOT EXISTS IDX_${tablePrefixPure}ca4a71b47f28ac6ea88293a8e2 ON ${tablePrefix}execution_entity ("waitTill")`); + } + + async down(queryRunner: QueryRunner): Promise { + let tablePrefix = config.get('database.tablePrefix'); + const tablePrefixPure = tablePrefix; + const schema = config.get('database.postgresdb.schema'); + if (schema) { + tablePrefix = schema + '.' + tablePrefix; + } + + await queryRunner.query(`DROP INDEX IDX_${tablePrefixPure}ca4a71b47f28ac6ea88293a8e2`); + await queryRunner.query(`ALTER TABLE ${tablePrefix}webhook_entity DROP COLUMN "waitTill"`); + } + +} diff --git a/packages/cli/src/databases/postgresdb/migrations/index.ts b/packages/cli/src/databases/postgresdb/migrations/index.ts index 0f6cc669c9..83983dd039 100644 --- a/packages/cli/src/databases/postgresdb/migrations/index.ts +++ b/packages/cli/src/databases/postgresdb/migrations/index.ts @@ -5,6 +5,7 @@ import { AddWebhookId1611144599516 } from './1611144599516-AddWebhookId'; import { MakeStoppedAtNullable1607431743768 } from './1607431743768-MakeStoppedAtNullable'; import { CreateTagEntity1617270242566 } from './1617270242566-CreateTagEntity'; import { UniqueWorkflowNames1620824779533 } from './1620824779533-UniqueWorkflowNames'; +import { AddwaitTill1626176912946 } from './1626176912946-AddwaitTill'; export const postgresMigrations = [ InitialMigration1587669153312, @@ -14,4 +15,5 @@ export const postgresMigrations = [ MakeStoppedAtNullable1607431743768, CreateTagEntity1617270242566, UniqueWorkflowNames1620824779533, + AddwaitTill1626176912946, ]; diff --git a/packages/cli/src/databases/sqlite/migrations/1621707690587-AddWaitColumn.ts b/packages/cli/src/databases/sqlite/migrations/1621707690587-AddWaitColumn.ts new file mode 100644 index 0000000000..17ed2c2a9a --- /dev/null +++ b/packages/cli/src/databases/sqlite/migrations/1621707690587-AddWaitColumn.ts @@ -0,0 +1,31 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import * as config from '../../../../config'; + +export class AddWaitColumn1621707690587 implements MigrationInterface { + name = 'AddWaitColumn1621707690587'; + + async up(queryRunner: QueryRunner): Promise { + const tablePrefix = config.get('database.tablePrefix'); + + await queryRunner.query(`CREATE TABLE IF NOT EXISTS "${tablePrefix}temporary_execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime, "workflowData" text NOT NULL, "workflowId" varchar, "waitTill" DATETIME)`, undefined); + await queryRunner.query(`INSERT INTO "${tablePrefix}temporary_execution_entity"("id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId") SELECT "id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId" FROM "${tablePrefix}execution_entity"`); + await queryRunner.query(`DROP TABLE "${tablePrefix}execution_entity"`); + await queryRunner.query(`ALTER TABLE "${tablePrefix}temporary_execution_entity" RENAME TO "${tablePrefix}execution_entity"`); + await queryRunner.query(`CREATE INDEX "IDX_${tablePrefix}cefb067df2402f6aed0638a6c1" ON "${tablePrefix}execution_entity" ("stoppedAt")`); + await queryRunner.query(`CREATE INDEX "IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2" ON "${tablePrefix}execution_entity" ("waitTill")`); + await queryRunner.query(`VACUUM;`); + } + + async down(queryRunner: QueryRunner): Promise { + const tablePrefix = config.get('database.tablePrefix'); + + await queryRunner.query(`CREATE TABLE IF NOT EXISTS "${tablePrefix}temporary_execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime, "workflowData" text NOT NULL, "workflowId" varchar)`, undefined); + await queryRunner.query(`INSERT INTO "${tablePrefix}temporary_execution_entity"("id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId") SELECT "id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId" FROM "${tablePrefix}execution_entity"`); + await queryRunner.query(`DROP TABLE "${tablePrefix}execution_entity"`); + await queryRunner.query(`ALTER TABLE "${tablePrefix}temporary_execution_entity" RENAME TO "${tablePrefix}execution_entity"`); + await queryRunner.query(`CREATE INDEX "IDX_${tablePrefix}cefb067df2402f6aed0638a6c1" ON "${tablePrefix}execution_entity" ("stoppedAt")`); + await queryRunner.query(`VACUUM;`); + + } + +} diff --git a/packages/cli/src/databases/sqlite/migrations/index.ts b/packages/cli/src/databases/sqlite/migrations/index.ts index 14b5184954..64038d9e30 100644 --- a/packages/cli/src/databases/sqlite/migrations/index.ts +++ b/packages/cli/src/databases/sqlite/migrations/index.ts @@ -5,6 +5,7 @@ import { AddWebhookId1611071044839 } from './1611071044839-AddWebhookId'; import { MakeStoppedAtNullable1607431743769 } from './1607431743769-MakeStoppedAtNullable'; import { CreateTagEntity1617213344594 } from './1617213344594-CreateTagEntity'; import { UniqueWorkflowNames1620821879465 } from './1620821879465-UniqueWorkflowNames'; +import { AddWaitColumn1621707690587 } from './1621707690587-AddWaitColumn'; export const sqliteMigrations = [ InitialMigration1588102412422, @@ -14,4 +15,5 @@ export const sqliteMigrations = [ MakeStoppedAtNullable1607431743769, CreateTagEntity1617213344594, UniqueWorkflowNames1620821879465, + AddWaitColumn1621707690587, ]; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index cc7e942fe5..296348cf65 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -5,6 +5,8 @@ export * from './ExternalHooks'; export * from './Interfaces'; export * from './LoadNodesAndCredentials'; export * from './NodeTypes'; +export * from './WaitTracker'; +export * from './WaitingWebhooks'; export * from './WorkflowCredentials'; export * from './WorkflowRunner'; diff --git a/packages/core/src/Constants.ts b/packages/core/src/Constants.ts index a11b6d9402..4e72f53f9c 100644 --- a/packages/core/src/Constants.ts +++ b/packages/core/src/Constants.ts @@ -5,4 +5,6 @@ export const EXTENSIONS_SUBDIRECTORY = 'custom'; export const USER_FOLDER_ENV_OVERWRITE = 'N8N_USER_FOLDER'; export const USER_SETTINGS_FILE_NAME = 'config'; export const USER_SETTINGS_SUBFOLDER = '.n8n'; +export const PLACEHOLDER_EMPTY_EXECUTION_ID = '__UNKOWN__'; export const TUNNEL_SUBDOMAIN_ENV = 'N8N_TUNNEL_SUBDOMAIN'; +export const WAIT_TIME_UNLIMITED = '3000-01-01T00:00:00.000Z'; diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index cb94d6c2d2..582f5ac1ca 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -4,6 +4,7 @@ import { ILoadOptionsFunctions, IResponseError, IWorkflowSettings, + PLACEHOLDER_EMPTY_EXECUTION_ID, } from './'; import { @@ -28,6 +29,7 @@ import { IWebhookData, IWebhookDescription, IWebhookFunctions, + IWorkflowDataProxyAdditionalKeys, IWorkflowDataProxyData, IWorkflowExecuteAdditionalData, IWorkflowMetadata, @@ -322,6 +324,23 @@ export function returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExe +/** + * Returns the additional keys for Expressions and Function-Nodes + * + * @export + * @param {IWorkflowExecuteAdditionalData} additionalData + * @returns {(IWorkflowDataProxyAdditionalKeys)} + */ +export function getAdditionalKeys(additionalData: IWorkflowExecuteAdditionalData): IWorkflowDataProxyAdditionalKeys { + const executionId = additionalData.executionId || PLACEHOLDER_EMPTY_EXECUTION_ID; + return { + $executionId: executionId, + $resumeWebhookUrl: `${additionalData.webhookWaitingBaseUrl}/${executionId}`, + }; +} + + + /** * Returns the requested decrypted credentials if the node has access to them. * @@ -420,7 +439,7 @@ export function getNode(node: INode): INode { * @param {*} [fallbackValue] * @returns {(NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object)} */ -export function getNodeParameter(workflow: Workflow, runExecutionData: IRunExecutionData | null, runIndex: number, connectionInputData: INodeExecutionData[], node: INode, parameterName: string, itemIndex: number, mode: WorkflowExecuteMode, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object { //tslint:disable-line:no-any +export function getNodeParameter(workflow: Workflow, runExecutionData: IRunExecutionData | null, runIndex: number, connectionInputData: INodeExecutionData[], node: INode, parameterName: string, itemIndex: number, mode: WorkflowExecuteMode, additionalKeys: IWorkflowDataProxyAdditionalKeys, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object { //tslint:disable-line:no-any const nodeType = workflow.nodeTypes.getByName(node.type); if (nodeType === undefined) { throw new Error(`Node type "${node.type}" is not known so can not return paramter value!`); @@ -434,7 +453,7 @@ export function getNodeParameter(workflow: Workflow, runExecutionData: IRunExecu let returnData; try { - returnData = workflow.expression.getParameterValue(value, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode); + returnData = workflow.expression.getParameterValue(value, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode, additionalKeys); } catch (e) { e.message += ` [Error in parameter: "${parameterName}"]`; throw e; @@ -469,7 +488,7 @@ export function continueOnFail(node: INode): boolean { * @param {boolean} [isTest] * @returns {(string | undefined)} */ -export function getNodeWebhookUrl(name: string, workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, isTest?: boolean): string | undefined { +export function getNodeWebhookUrl(name: string, workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, additionalKeys: IWorkflowDataProxyAdditionalKeys, isTest?: boolean): string | undefined { let baseUrl = additionalData.webhookBaseUrl; if (isTest === true) { baseUrl = additionalData.webhookTestBaseUrl; @@ -480,12 +499,12 @@ export function getNodeWebhookUrl(name: string, workflow: Workflow, node: INode, return undefined; } - const path = workflow.expression.getSimpleParameterValue(node, webhookDescription['path'], mode); + const path = workflow.expression.getSimpleParameterValue(node, webhookDescription['path'], mode, additionalKeys); if (path === undefined) { return undefined; } - const isFullPath: boolean = workflow.expression.getSimpleParameterValue(node, webhookDescription['isFullPath'], mode, false) as boolean; + const isFullPath: boolean = workflow.expression.getSimpleParameterValue(node, webhookDescription['isFullPath'], mode, additionalKeys, false) as boolean; return NodeHelpers.getNodeWebhookUrl(baseUrl, workflow.id!, node, path.toString(), isFullPath); } @@ -588,7 +607,7 @@ export function getExecutePollFunctions(workflow: Workflow, node: INode, additio const runIndex = 0; const connectionInputData: INodeExecutionData[] = []; - return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, fallbackValue); + return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, getAdditionalKeys(additionalData), fallbackValue); }, getRestApiUrl: (): string => { return additionalData.restApiUrl; @@ -654,7 +673,7 @@ export function getExecuteTriggerFunctions(workflow: Workflow, node: INode, addi const runIndex = 0; const connectionInputData: INodeExecutionData[] = []; - return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, fallbackValue); + return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, getAdditionalKeys(additionalData), fallbackValue); }, getRestApiUrl: (): string => { return additionalData.restApiUrl; @@ -706,7 +725,7 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx return continueOnFail(node); }, evaluateExpression: (expression: string, itemIndex: number) => { - return workflow.expression.resolveSimpleParameterValue('=' + expression, {}, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode); + return workflow.expression.resolveSimpleParameterValue('=' + expression, {}, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode, getAdditionalKeys(additionalData)); }, async executeWorkflow(workflowInfo: IExecuteWorkflowInfo, inputData?: INodeExecutionData[]): Promise { // tslint:disable-line:no-any return additionalData.executeWorkflow(workflowInfo, additionalData, inputData); @@ -717,6 +736,9 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx async getCredentials(type: string, itemIndex?: number): Promise { return await getCredentials(workflow, node, type, additionalData, mode, runExecutionData, runIndex, connectionInputData, itemIndex); }, + getExecutionId: (): string => { + return additionalData.executionId!; + }, getInputData: (inputIndex = 0, inputName = 'main') => { if (!inputData.hasOwnProperty(inputName)) { @@ -729,17 +751,15 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx throw new Error(`Could not get input index "${inputIndex}" of input "${inputName}"!`); } - if (inputData[inputName][inputIndex] === null) { // return []; throw new Error(`Value "${inputIndex}" of input "${inputName}" did not get set!`); } - // TODO: Maybe do clone of data only here so it only clones the data that is really needed return inputData[inputName][inputIndex] as INodeExecutionData[]; }, getNodeParameter: (parameterName: string, itemIndex: number, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object => { //tslint:disable-line:no-any - return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, fallbackValue); + return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, getAdditionalKeys(additionalData), fallbackValue); }, getMode: (): WorkflowExecuteMode => { return mode; @@ -757,14 +777,17 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx return getWorkflowMetadata(workflow); }, getWorkflowDataProxy: (itemIndex: number): IWorkflowDataProxyData => { - const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, {}, mode); + const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, {}, mode, getAdditionalKeys(additionalData)); return dataProxy.getDataProxy(); }, getWorkflowStaticData(type: string): IDataObject { return workflow.getStaticData(type, node); }, prepareOutputData: NodeHelpers.prepareOutputData, - sendMessageToUI(message: any): void { // tslint:disable-line:no-any + async putExecutionToWait(waitTill: Date): Promise { + runExecutionData.waitTill = waitTill; + }, + sendMessageToUI(message : any): void { // tslint:disable-line:no-any if (mode !== 'manual') { return; } @@ -819,7 +842,7 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData: }, evaluateExpression: (expression: string, evaluateItemIndex: number | undefined) => { evaluateItemIndex = evaluateItemIndex === undefined ? itemIndex : evaluateItemIndex; - return workflow.expression.resolveSimpleParameterValue('=' + expression, {}, runExecutionData, runIndex, evaluateItemIndex, node.name, connectionInputData, mode); + return workflow.expression.resolveSimpleParameterValue('=' + expression, {}, runExecutionData, runIndex, evaluateItemIndex, node.name, connectionInputData, mode, getAdditionalKeys(additionalData)); }, getContext(type: string): IContextObject { return NodeHelpers.getContext(runExecutionData, type, node); @@ -865,13 +888,13 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData: return getTimezone(workflow, additionalData); }, getNodeParameter: (parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object => { //tslint:disable-line:no-any - return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, fallbackValue); + return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, getAdditionalKeys(additionalData), fallbackValue); }, getWorkflow: () => { return getWorkflowMetadata(workflow); }, getWorkflowDataProxy: (): IWorkflowDataProxyData => { - const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, {}, mode); + const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, {}, mode, getAdditionalKeys(additionalData)); return dataProxy.getDataProxy(); }, getWorkflowStaticData(type: string): IDataObject { @@ -928,7 +951,7 @@ export function getLoadOptionsFunctions(workflow: Workflow, node: INode, path: s const runIndex = 0; const connectionInputData: INodeExecutionData[] = []; - return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, 'internal' as WorkflowExecuteMode, fallbackValue); + return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, 'internal' as WorkflowExecuteMode, getAdditionalKeys(additionalData), fallbackValue); }, getTimezone: (): string => { return getTimezone(workflow, additionalData); @@ -983,10 +1006,10 @@ export function getExecuteHookFunctions(workflow: Workflow, node: INode, additio const runIndex = 0; const connectionInputData: INodeExecutionData[] = []; - return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, fallbackValue); + return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, getAdditionalKeys(additionalData), fallbackValue); }, getNodeWebhookUrl: (name: string): string | undefined => { - return getNodeWebhookUrl(name, workflow, node, additionalData, mode, isTest); + return getNodeWebhookUrl(name, workflow, node, additionalData, mode, getAdditionalKeys(additionalData), isTest); }, getTimezone: (): string => { return getTimezone(workflow, additionalData); @@ -1063,7 +1086,7 @@ export function getExecuteWebhookFunctions(workflow: Workflow, node: INode, addi const runIndex = 0; const connectionInputData: INodeExecutionData[] = []; - return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, fallbackValue); + return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, mode, getAdditionalKeys(additionalData), fallbackValue); }, getParamsData(): object { if (additionalData.httpRequest === undefined) { @@ -1090,7 +1113,7 @@ export function getExecuteWebhookFunctions(workflow: Workflow, node: INode, addi return additionalData.httpResponse; }, getNodeWebhookUrl: (name: string): string | undefined => { - return getNodeWebhookUrl(name, workflow, node, additionalData, mode); + return getNodeWebhookUrl(name, workflow, node, additionalData, mode, getAdditionalKeys(additionalData)); }, getTimezone: (): string => { return getTimezone(workflow, additionalData); diff --git a/packages/core/src/WorkflowExecute.ts b/packages/core/src/WorkflowExecute.ts index b893b85cb0..a3e78b022b 100644 --- a/packages/core/src/WorkflowExecute.ts +++ b/packages/core/src/WorkflowExecute.ts @@ -31,7 +31,6 @@ export class WorkflowExecute { private additionalData: IWorkflowExecuteAdditionalData; private mode: WorkflowExecuteMode; - constructor(additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, runExecutionData?: IRunExecutionData) { this.additionalData = additionalData; this.mode = mode; @@ -512,6 +511,13 @@ export class WorkflowExecute { this.runExecutionData.startData = {}; } + if (this.runExecutionData.waitTill) { + const lastNodeExecuted = this.runExecutionData.resultData.lastNodeExecuted as string; + this.runExecutionData.executionData!.nodeExecutionStack[0].node.disabled = true; + this.runExecutionData.waitTill = undefined; + this.runExecutionData.resultData.runData[lastNodeExecuted].pop(); + } + let currentExecutionTry = ''; let lastExecutionTry = ''; @@ -693,7 +699,7 @@ export class WorkflowExecute { } } - if (nodeSuccessData === null) { + if (nodeSuccessData === null && !this.runExecutionData.waitTill!!) { // If null gets returned it means that the node did succeed // but did not have any data. So the branch should end // (meaning the nodes afterwards should not be processed) @@ -767,6 +773,15 @@ export class WorkflowExecute { continue; } + if (this.runExecutionData.waitTill!!) { + await this.executeHook('nodeExecuteAfter', [executionNode.name, taskData, this.runExecutionData]); + + // Add the node back to the stack that the workflow can start to execute again from that node + this.runExecutionData.executionData!.nodeExecutionStack.unshift(executionData); + + break; + } + // Add the nodes to which the current node has an output connection to that they can // be executed next if (workflow.connectionsBySourceNode.hasOwnProperty(executionNode.name)) { @@ -849,6 +864,9 @@ export class WorkflowExecute { message: executionError.message, stack: executionError.stack, } as ExecutionError; + } else if (this.runExecutionData.waitTill!!) { + Logger.verbose(`Workflow execution will wait until ${this.runExecutionData.waitTill}`, { workflowId: workflow.id }); + fullRunData.waitTill = this.runExecutionData.waitTill; } else { Logger.verbose(`Workflow execution finished successfully`, { workflowId: workflow.id }); fullRunData.finished = true; diff --git a/packages/core/test/Helpers.ts b/packages/core/test/Helpers.ts index b5662a24e7..ce59151abc 100644 --- a/packages/core/test/Helpers.ts +++ b/packages/core/test/Helpers.ts @@ -758,6 +758,7 @@ export function WorkflowExecuteAdditionalData(waitPromise: IDeferredPromise