From f2ceb8aa881bccf62cdbad846db142f5db9fd39c Mon Sep 17 00:00:00 2001 From: Matheus Cansian Date: Fri, 4 Oct 2019 17:01:25 -0300 Subject: [PATCH 01/10] Add AWS credentials --- .../nodes-base/credentials/Aws.credentials.ts | 33 +++++++++++++++++++ packages/nodes-base/package.json | 1 + 2 files changed, 34 insertions(+) create mode 100644 packages/nodes-base/credentials/Aws.credentials.ts diff --git a/packages/nodes-base/credentials/Aws.credentials.ts b/packages/nodes-base/credentials/Aws.credentials.ts new file mode 100644 index 000000000..6a0f294b8 --- /dev/null +++ b/packages/nodes-base/credentials/Aws.credentials.ts @@ -0,0 +1,33 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + + +export class Aws implements ICredentialType { + name = 'aws'; + displayName = 'AWS'; + properties = [ + { + displayName: 'Region', + name: 'region', + type: 'string' as NodePropertyTypes, + default: 'us-east-1', + }, + { + displayName: 'Access Key Id', + name: 'accessKeyId', + type: 'string' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Secret Access Key', + name: 'secretAccessKey', + type: 'string' as NodePropertyTypes, + default: '', + typeOptions: { + password: true, + }, + }, + ]; +} diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 2fa37e795..5729e7a36 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -29,6 +29,7 @@ "dist/credentials/ActiveCampaignApi.credentials.js", "dist/credentials/AirtableApi.credentials.js", "dist/credentials/AsanaApi.credentials.js", + "dist/credentials/Aws.credentials.js", "dist/credentials/ChargebeeApi.credentials.js", "dist/credentials/DropboxApi.credentials.js", "dist/credentials/GithubApi.credentials.js", From ec9d65b2e016299de625b20a364e55bfa6524f25 Mon Sep 17 00:00:00 2001 From: Matheus Cansian Date: Fri, 4 Oct 2019 22:06:26 -0300 Subject: [PATCH 02/10] Implement AWS SNS node --- packages/nodes-base/nodes/Aws/Sns.node.ts | 152 ++++++++++++++++++++++ packages/nodes-base/nodes/Aws/sns.png | Bin 0 -> 6032 bytes packages/nodes-base/package.json | 2 + 3 files changed, 154 insertions(+) create mode 100644 packages/nodes-base/nodes/Aws/Sns.node.ts create mode 100644 packages/nodes-base/nodes/Aws/sns.png diff --git a/packages/nodes-base/nodes/Aws/Sns.node.ts b/packages/nodes-base/nodes/Aws/Sns.node.ts new file mode 100644 index 000000000..e8404b154 --- /dev/null +++ b/packages/nodes-base/nodes/Aws/Sns.node.ts @@ -0,0 +1,152 @@ +import { + SNS, + config, + AWSError, +} from 'aws-sdk'; +import { IExecuteFunctions } from 'n8n-core'; +import { + INodeTypeDescription, + INodeExecutionData, + INodeType, + INodePropertyOptions, + ILoadOptionsFunctions, + IDataObject +} from 'n8n-workflow'; + +export class Sns implements INodeType { + description: INodeTypeDescription = { + displayName: 'Amazon SNS', + name: 'amazonSns', + icon: 'file:sns.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["topic"]}}', + description: 'Sends data to Amazon SNS', + defaults: { + name: 'Amazon SNS', + color: '#BB2244', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'aws', + required: true, + } + ], + properties: [ + { + displayName: 'Topic', + name: 'topic', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getTopics', + }, + options: [], + default: '', + required: true, + description: 'The topic you want to publish to', + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + description: 'Subject when the message is delivered to email endpoints', + }, + { + displayName: 'Message', + name: 'message', + type: 'string', + required: true, + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + description: 'The message you want to send', + }, + ], + }; + + methods = { + loadOptions: { + // Get all the available topics to display them to user so that he can + // select them easily + async getTopics(this: ILoadOptionsFunctions): Promise { + const credentials = this.getCredentials('aws'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + config.update({ + region: `${credentials.region}`, + accessKeyId: `${credentials.accessKeyId}`, + secretAccessKey: `${credentials.secretAccessKey}`, + }); + + const returnData: INodePropertyOptions[] = []; + + let sns = new SNS(); + try { + var data = await sns.listTopics({}).promise(); + } catch (err) { + throw new Error(`AWS Error: ${err}`); + } + + for (let topic of data.Topics!) { + let topicArn = topic.TopicArn!; + let topicName = topicArn.split(':')[5]; + returnData.push({ + name: topicName, + value: topicArn, + }); + } + return returnData; + } + }, + }; + + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + + const credentials = this.getCredentials('aws'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + let topicArn: string; + let subject: string; + let message: string; + + config.update({ + region: `${credentials.region}`, + accessKeyId: `${credentials.accessKeyId}`, + secretAccessKey: `${credentials.secretAccessKey}`, + }); + let sns = new SNS(); + + for (let i = 0; i < items.length; i++) { + topicArn = this.getNodeParameter('topic', i) as string; + subject = this.getNodeParameter('subject', i) as string; + message = this.getNodeParameter('message', i) as string; + + let params = { + Message: message, + Subject: subject, + TopicArn: topicArn, + }; + + try { + var responseData = await sns.publish(params).promise(); + } catch (err) { + throw new Error(`AWS Error: ${err}`); + } + returnData.push(responseData as IDataObject); + } + + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Aws/sns.png b/packages/nodes-base/nodes/Aws/sns.png new file mode 100644 index 0000000000000000000000000000000000000000..1ebc137c321952831eb13285fa027189d5274cfc GIT binary patch literal 6032 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 Date: Sat, 5 Oct 2019 10:27:19 -0300 Subject: [PATCH 03/10] Improve code readability Aws node --- .../nodes-base/nodes/Aws/GenericFunctions.ts | 23 ++++++++ packages/nodes-base/nodes/Aws/Sns.node.ts | 55 +++++-------------- 2 files changed, 37 insertions(+), 41 deletions(-) create mode 100644 packages/nodes-base/nodes/Aws/GenericFunctions.ts diff --git a/packages/nodes-base/nodes/Aws/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/GenericFunctions.ts new file mode 100644 index 000000000..2bfd2c027 --- /dev/null +++ b/packages/nodes-base/nodes/Aws/GenericFunctions.ts @@ -0,0 +1,23 @@ +import { + IExecuteFunctions, + IHookFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; + +import { config } from 'aws-sdk'; +import { OptionsWithUri } from 'request'; + + +export async function awsConfigCredentials(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions): Promise { + const credentials = this.getCredentials('aws'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + config.update({ + region: `${credentials.region}`, + accessKeyId: `${credentials.accessKeyId}`, + secretAccessKey: `${credentials.secretAccessKey}`, + }); +} diff --git a/packages/nodes-base/nodes/Aws/Sns.node.ts b/packages/nodes-base/nodes/Aws/Sns.node.ts index e8404b154..bfde1f049 100644 --- a/packages/nodes-base/nodes/Aws/Sns.node.ts +++ b/packages/nodes-base/nodes/Aws/Sns.node.ts @@ -1,8 +1,3 @@ -import { - SNS, - config, - AWSError, -} from 'aws-sdk'; import { IExecuteFunctions } from 'n8n-core'; import { INodeTypeDescription, @@ -13,6 +8,10 @@ import { IDataObject } from 'n8n-workflow'; +import { awsConfigCredentials } from './GenericFunctions'; + +import { SNS } from 'aws-sdk'; + export class Sns implements INodeType { description: INodeTypeDescription = { displayName: 'Amazon SNS', @@ -24,7 +23,7 @@ export class Sns implements INodeType { description: 'Sends data to Amazon SNS', defaults: { name: 'Amazon SNS', - color: '#BB2244', + color: '#FF9900', }, inputs: ['main'], outputs: ['main'], @@ -73,17 +72,7 @@ export class Sns implements INodeType { // Get all the available topics to display them to user so that he can // select them easily async getTopics(this: ILoadOptionsFunctions): Promise { - const credentials = this.getCredentials('aws'); - - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } - - config.update({ - region: `${credentials.region}`, - accessKeyId: `${credentials.accessKeyId}`, - secretAccessKey: `${credentials.secretAccessKey}`, - }); + await awsConfigCredentials.call(this); const returnData: INodePropertyOptions[] = []; @@ -95,8 +84,9 @@ export class Sns implements INodeType { } for (let topic of data.Topics!) { - let topicArn = topic.TopicArn!; + let topicArn = topic.TopicArn as string; let topicName = topicArn.split(':')[5]; + returnData.push({ name: topicName, value: topicArn, @@ -112,31 +102,14 @@ export class Sns implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - const credentials = this.getCredentials('aws'); - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } - - let topicArn: string; - let subject: string; - let message: string; - - config.update({ - region: `${credentials.region}`, - accessKeyId: `${credentials.accessKeyId}`, - secretAccessKey: `${credentials.secretAccessKey}`, - }); - let sns = new SNS(); + await awsConfigCredentials.call(this); + const sns = new SNS(); for (let i = 0; i < items.length; i++) { - topicArn = this.getNodeParameter('topic', i) as string; - subject = this.getNodeParameter('subject', i) as string; - message = this.getNodeParameter('message', i) as string; - - let params = { - Message: message, - Subject: subject, - TopicArn: topicArn, + const params = { + TopicArn: this.getNodeParameter('topic', i) as string, + Subject: this.getNodeParameter('subject', i) as string, + Message: this.getNodeParameter('message', i) as string, }; try { From 4bde05f41737ae37ba0e3bc7e74fea82f86a8451 Mon Sep 17 00:00:00 2001 From: Matheus Cansian Date: Sat, 5 Oct 2019 12:03:18 -0300 Subject: [PATCH 04/10] Implement node for AWS Lambda --- .../nodes-base/nodes/Aws/AwsLambda.node.ts | 145 ++++++++++++++++++ packages/nodes-base/nodes/Aws/lambda.png | Bin 0 -> 11484 bytes 2 files changed, 145 insertions(+) create mode 100644 packages/nodes-base/nodes/Aws/AwsLambda.node.ts create mode 100644 packages/nodes-base/nodes/Aws/lambda.png diff --git a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts new file mode 100644 index 000000000..bcbbca63a --- /dev/null +++ b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts @@ -0,0 +1,145 @@ +import { IExecuteFunctions } from 'n8n-core'; +import { + INodeTypeDescription, + INodeExecutionData, + INodeType, + INodePropertyOptions, + ILoadOptionsFunctions, + IDataObject +} from 'n8n-workflow'; + +import { awsConfigCredentials } from './GenericFunctions'; + +import { Lambda } from 'aws-sdk'; + +export class AwsLambda implements INodeType { + description: INodeTypeDescription = { + displayName: 'AWS Lambda', + name: 'awsLambda', + icon: 'file:lambda.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["function"]}}', + description: 'Invoke functions on AWS Lambda', + defaults: { + name: 'AWS Lambda', + color: '#FF9900', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'aws', + required: true, + } + ], + properties: [ + { + displayName: 'Function', + name: 'function', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getFunctions', + }, + options: [], + default: '', + required: true, + description: 'The function you want to invoke', + }, + { + displayName: 'Qualifier', + name: 'qualifier', + type: 'string', + required: true, + default: '$LATEST', + description: 'Specify a version or alias to invoke a published version of the function', + }, + { + displayName: 'Invocation Type', + name: 'invocationType', + type: 'options', + options: [ + { + name: 'Wait for results', + value: 'RequestResponse', + description: 'Invoke the function synchronously and wait for the response', + }, + { + name: 'Continue workflow', + value: 'Event', + description: 'Invoke the function and immediately continue the workflow', + }, + ], + default: 'RequestResponse', + description: 'Specify if the workflow should wait for the function to return the results', + }, + { + displayName: 'JSON Input', + name: 'payload', + type: 'string', + default: '', + description: 'The JSON that you want to provide to your Lambda function as input', + typeOptions: { + alwaysOpenEditWindow: true, + }, + }, + ], + }; + + methods = { + loadOptions: { + async getFunctions(this: ILoadOptionsFunctions): Promise { + await awsConfigCredentials.call(this); + + const returnData: INodePropertyOptions[] = []; + + let lambda = new Lambda(); + try { + var data = await lambda.listFunctions({}).promise(); + } catch (err) { + throw new Error(`AWS Error: ${err}`); + } + + for (let func of data.Functions!) { + returnData.push({ + name: func.FunctionName as string, + value: func.FunctionArn as string, + }); + } + return returnData; + } + }, + }; + + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + + await awsConfigCredentials.call(this); + const lambda = new Lambda(); + + for (let i = 0; i < items.length; i++) { + const params = { + FunctionName: this.getNodeParameter('function', i) as string, + InvocationType: this.getNodeParameter('invocationType', i) as string, + Payload: this.getNodeParameter('payload', i) as string, + Qualifier: this.getNodeParameter('qualifier', i) as string, + }; + + try { + var responseData = await lambda.invoke(params).promise(); + } catch (err) { + throw new Error(`AWS Error: ${err}`); + } + + returnData.push({ + StatusCode: responseData.StatusCode, + Result: responseData.Payload, + Error: responseData.FunctionError, + } as IDataObject); + } + + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Aws/lambda.png b/packages/nodes-base/nodes/Aws/lambda.png new file mode 100644 index 0000000000000000000000000000000000000000..d98d8f3cdc7155a79afe72174ee41d215023575b GIT binary patch literal 11484 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 Date: Sat, 5 Oct 2019 12:05:58 -0300 Subject: [PATCH 05/10] Rename amazonSns to awsSns --- .../nodes/Aws/{Sns.node.ts => AwsSns.node.ts} | 10 +++++----- packages/nodes-base/package.json | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) rename packages/nodes-base/nodes/Aws/{Sns.node.ts => AwsSns.node.ts} (94%) diff --git a/packages/nodes-base/nodes/Aws/Sns.node.ts b/packages/nodes-base/nodes/Aws/AwsSns.node.ts similarity index 94% rename from packages/nodes-base/nodes/Aws/Sns.node.ts rename to packages/nodes-base/nodes/Aws/AwsSns.node.ts index bfde1f049..2e98a1b2f 100644 --- a/packages/nodes-base/nodes/Aws/Sns.node.ts +++ b/packages/nodes-base/nodes/Aws/AwsSns.node.ts @@ -12,17 +12,17 @@ import { awsConfigCredentials } from './GenericFunctions'; import { SNS } from 'aws-sdk'; -export class Sns implements INodeType { +export class AwsSns implements INodeType { description: INodeTypeDescription = { - displayName: 'Amazon SNS', - name: 'amazonSns', + displayName: 'AWS SNS', + name: 'awsSns', icon: 'file:sns.png', group: ['output'], version: 1, subtitle: '={{$parameter["topic"]}}', - description: 'Sends data to Amazon SNS', + description: 'Sends data to AWS SNS', defaults: { - name: 'Amazon SNS', + name: 'AWS SNS', color: '#FF9900', }, inputs: ['main'], diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 444cf7a58..54a83b531 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -56,7 +56,8 @@ "dist/nodes/Airtable/Airtable.node.js", "dist/nodes/Asana/Asana.node.js", "dist/nodes/Asana/AsanaTrigger.node.js", - "dist/nodes/Aws/Sns.node.js", + "dist/nodes/Aws/AwsLambda.node.js", + "dist/nodes/Aws/AwsSns.node.js", "dist/nodes/Chargebee/Chargebee.node.js", "dist/nodes/Chargebee/ChargebeeTrigger.node.js", "dist/nodes/Cron.node.js", From d3320e341159446e317787212d2b121e11332059 Mon Sep 17 00:00:00 2001 From: Matheus Cansian Date: Sat, 5 Oct 2019 12:09:03 -0300 Subject: [PATCH 06/10] Remove ResponseMetadata from SNS node results --- packages/nodes-base/nodes/Aws/AwsSns.node.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/nodes/Aws/AwsSns.node.ts b/packages/nodes-base/nodes/Aws/AwsSns.node.ts index 2e98a1b2f..ad25539b6 100644 --- a/packages/nodes-base/nodes/Aws/AwsSns.node.ts +++ b/packages/nodes-base/nodes/Aws/AwsSns.node.ts @@ -117,7 +117,7 @@ export class AwsSns implements INodeType { } catch (err) { throw new Error(`AWS Error: ${err}`); } - returnData.push(responseData as IDataObject); + returnData.push({MessageId: responseData.MessageId} as IDataObject); } return [this.helpers.returnJsonArray(returnData)]; From 822e12ff35081392d4e70bcfc61f27a6d7ba74c6 Mon Sep 17 00:00:00 2001 From: Matheus Cansian Date: Sat, 5 Oct 2019 12:10:12 -0300 Subject: [PATCH 07/10] Fix identation --- .../nodes-base/nodes/Aws/AwsLambda.node.ts | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts index bcbbca63a..87685c75b 100644 --- a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts +++ b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts @@ -46,42 +46,42 @@ export class AwsLambda implements INodeType { required: true, description: 'The function you want to invoke', }, - { - displayName: 'Qualifier', - name: 'qualifier', - type: 'string', - required: true, - default: '$LATEST', - description: 'Specify a version or alias to invoke a published version of the function', - }, - { - displayName: 'Invocation Type', - name: 'invocationType', - type: 'options', - options: [ - { - name: 'Wait for results', - value: 'RequestResponse', - description: 'Invoke the function synchronously and wait for the response', - }, - { - name: 'Continue workflow', - value: 'Event', - description: 'Invoke the function and immediately continue the workflow', - }, - ], - default: 'RequestResponse', - description: 'Specify if the workflow should wait for the function to return the results', - }, + { + displayName: 'Qualifier', + name: 'qualifier', + type: 'string', + required: true, + default: '$LATEST', + description: 'Specify a version or alias to invoke a published version of the function', + }, + { + displayName: 'Invocation Type', + name: 'invocationType', + type: 'options', + options: [ + { + name: 'Wait for results', + value: 'RequestResponse', + description: 'Invoke the function synchronously and wait for the response', + }, + { + name: 'Continue workflow', + value: 'Event', + description: 'Invoke the function and immediately continue the workflow', + }, + ], + default: 'RequestResponse', + description: 'Specify if the workflow should wait for the function to return the results', + }, { displayName: 'JSON Input', name: 'payload', type: 'string', default: '', description: 'The JSON that you want to provide to your Lambda function as input', - typeOptions: { - alwaysOpenEditWindow: true, - }, + typeOptions: { + alwaysOpenEditWindow: true, + }, }, ], }; @@ -121,10 +121,10 @@ export class AwsLambda implements INodeType { for (let i = 0; i < items.length; i++) { const params = { - FunctionName: this.getNodeParameter('function', i) as string, - InvocationType: this.getNodeParameter('invocationType', i) as string, - Payload: this.getNodeParameter('payload', i) as string, - Qualifier: this.getNodeParameter('qualifier', i) as string, + FunctionName: this.getNodeParameter('function', i) as string, + InvocationType: this.getNodeParameter('invocationType', i) as string, + Payload: this.getNodeParameter('payload', i) as string, + Qualifier: this.getNodeParameter('qualifier', i) as string, }; try { @@ -134,10 +134,10 @@ export class AwsLambda implements INodeType { } returnData.push({ - StatusCode: responseData.StatusCode, - Result: responseData.Payload, - Error: responseData.FunctionError, - } as IDataObject); + StatusCode: responseData.StatusCode, + Result: responseData.Payload, + Error: responseData.FunctionError, + } as IDataObject); } return [this.helpers.returnJsonArray(returnData)]; From 39c0b08d9db707bd9bd5fc86fd462c64142f2927 Mon Sep 17 00:00:00 2001 From: Matheus Cansian Date: Sat, 5 Oct 2019 17:17:23 -0300 Subject: [PATCH 08/10] Remove aws-sdk dependency from AWS Lambda node --- .../nodes-base/nodes/Aws/AwsLambda.node.ts | 45 ++++++++++++------ .../nodes-base/nodes/Aws/GenericFunctions.ts | 47 ++++++++++++++++++- packages/nodes-base/package.json | 2 + 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts index 87685c75b..70e254342 100644 --- a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts +++ b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts @@ -8,7 +8,7 @@ import { IDataObject } from 'n8n-workflow'; -import { awsConfigCredentials } from './GenericFunctions'; +import { awsApiRequest } from './GenericFunctions'; import { Lambda } from 'aws-sdk'; @@ -89,13 +89,9 @@ export class AwsLambda implements INodeType { methods = { loadOptions: { async getFunctions(this: ILoadOptionsFunctions): Promise { - await awsConfigCredentials.call(this); - const returnData: INodePropertyOptions[] = []; - - let lambda = new Lambda(); try { - var data = await lambda.listFunctions({}).promise(); + var data = await awsApiRequest.call(this, 'lambda', 'GET', '/2015-03-31/functions/'); } catch (err) { throw new Error(`AWS Error: ${err}`); } @@ -116,9 +112,6 @@ export class AwsLambda implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - await awsConfigCredentials.call(this); - const lambda = new Lambda(); - for (let i = 0; i < items.length; i++) { const params = { FunctionName: this.getNodeParameter('function', i) as string, @@ -128,16 +121,38 @@ export class AwsLambda implements INodeType { }; try { - var responseData = await lambda.invoke(params).promise(); + + var responseData = await awsApiRequest.call( + this, + 'lambda', + 'POST', + `/2015-03-31/functions/${params.FunctionName}/invocations?Qualifier=${params.Qualifier}`, + params.Payload, + { + 'X-Amz-Invocation-Type': params.InvocationType, + 'Content-Type': 'application/x-amz-json-1.0', + }, + ); } catch (err) { throw new Error(`AWS Error: ${err}`); } - returnData.push({ - StatusCode: responseData.StatusCode, - Result: responseData.Payload, - Error: responseData.FunctionError, - } as IDataObject); + if (responseData.errorMessage === undefined) { + returnData.push({ + FunctionName: params.FunctionName, + FunctionQualifier: params.Qualifier, + Result: responseData, + } as IDataObject); + } else { + returnData.push({ + FunctionName: params.FunctionName, + FunctionQualifier: params.Qualifier, + ErrorMessage: responseData.errorMessage, + ErrorType: responseData.errorType, + ErrorStackTrace: responseData.stackTrace, + } as IDataObject); + } + } return [this.helpers.returnJsonArray(returnData)]; diff --git a/packages/nodes-base/nodes/Aws/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/GenericFunctions.ts index 2bfd2c027..30b3f2f94 100644 --- a/packages/nodes-base/nodes/Aws/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/GenericFunctions.ts @@ -6,7 +6,7 @@ import { import { config } from 'aws-sdk'; import { OptionsWithUri } from 'request'; - +import { sign } from 'aws4'; export async function awsConfigCredentials(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions): Promise { const credentials = this.getCredentials('aws'); @@ -21,3 +21,48 @@ export async function awsConfigCredentials(this: IHookFunctions | IExecuteFuncti secretAccessKey: `${credentials.secretAccessKey}`, }); } + +export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any + const credentials = this.getCredentials('aws'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const endpoint = `${service}.${credentials.region}.amazonaws.com` + + // Sign AWS API request with the user credentials + const signOpts = {headers: headers || {}, host: endpoint, method: method, path: path, body: body} + sign(signOpts, {accessKeyId: `${credentials.accessKeyId}`, secretAccessKey: `${credentials.secretAccessKey}`}) + + const options: OptionsWithUri = { + headers: signOpts.headers, + method: method, + uri: `https://${endpoint}${signOpts.path}`, + body: signOpts.body, + }; + + let response: string + try { + response = await this.helpers.request!(options); + } catch (error) { + console.error(error); + + const errorMessage = error.response.body.message || error.response.body.Message; + if (error.statusCode === 403) { + if (errorMessage == 'The security token included in the request is invalid.') { + throw new Error('The AWS credentials are not valid!'); + } else if (errorMessage.startsWith('The request signature we calculated does not match the signature you provided')) { + throw new Error('The AWS credentials are not valid!'); + } + } + + throw errorMessage; + } + + try { + return JSON.parse(response); + } catch (e) { + return response + } +} diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 54a83b531..4ee7ae8d6 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -106,6 +106,7 @@ ] }, "devDependencies": { + "@types/aws4": "^1.5.1", "@types/basic-auth": "^1.1.2", "@types/cron": "^1.6.1", "@types/express": "^4.16.1", @@ -126,6 +127,7 @@ "typescript": "~3.5.2" }, "dependencies": { + "aws4": "^1.8.0", "aws-sdk": "^2.543.0", "basic-auth": "^2.0.1", "cron": "^1.6.0", From 0fcbe409b6cfb985d52afb807ca9caa8fd3a4b10 Mon Sep 17 00:00:00 2001 From: Matheus Cansian Date: Tue, 15 Oct 2019 14:21:48 -0300 Subject: [PATCH 09/10] Remove aws-sdk dependency --- .../nodes-base/nodes/Aws/AwsLambda.node.ts | 9 ++-- packages/nodes-base/nodes/Aws/AwsSns.node.ts | 31 +++++-------- .../nodes-base/nodes/Aws/GenericFunctions.ts | 45 +++++++++++-------- packages/nodes-base/package.json | 1 - 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts index 70e254342..312316a7d 100644 --- a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts +++ b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts @@ -8,9 +8,7 @@ import { IDataObject } from 'n8n-workflow'; -import { awsApiRequest } from './GenericFunctions'; - -import { Lambda } from 'aws-sdk'; +import { awsApiRequestREST } from './GenericFunctions'; export class AwsLambda implements INodeType { description: INodeTypeDescription = { @@ -91,7 +89,7 @@ export class AwsLambda implements INodeType { async getFunctions(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; try { - var data = await awsApiRequest.call(this, 'lambda', 'GET', '/2015-03-31/functions/'); + var data = await awsApiRequestREST.call(this, 'lambda', 'GET', '/2015-03-31/functions/'); } catch (err) { throw new Error(`AWS Error: ${err}`); } @@ -121,8 +119,7 @@ export class AwsLambda implements INodeType { }; try { - - var responseData = await awsApiRequest.call( + var responseData = await awsApiRequestREST.call( this, 'lambda', 'POST', diff --git a/packages/nodes-base/nodes/Aws/AwsSns.node.ts b/packages/nodes-base/nodes/Aws/AwsSns.node.ts index ad25539b6..7b12184b6 100644 --- a/packages/nodes-base/nodes/Aws/AwsSns.node.ts +++ b/packages/nodes-base/nodes/Aws/AwsSns.node.ts @@ -8,9 +8,7 @@ import { IDataObject } from 'n8n-workflow'; -import { awsConfigCredentials } from './GenericFunctions'; - -import { SNS } from 'aws-sdk'; +import { awsApiRequestSOAP } from './GenericFunctions'; export class AwsSns implements INodeType { description: INodeTypeDescription = { @@ -51,6 +49,7 @@ export class AwsSns implements INodeType { name: 'subject', type: 'string', default: '', + required: true, description: 'Subject when the message is delivered to email endpoints', }, { @@ -72,18 +71,15 @@ export class AwsSns implements INodeType { // Get all the available topics to display them to user so that he can // select them easily async getTopics(this: ILoadOptionsFunctions): Promise { - await awsConfigCredentials.call(this); - const returnData: INodePropertyOptions[] = []; - - let sns = new SNS(); try { - var data = await sns.listTopics({}).promise(); + var data = await awsApiRequestSOAP.call(this, 'sns', 'GET', '/?Action=ListTopics'); } catch (err) { throw new Error(`AWS Error: ${err}`); } - for (let topic of data.Topics!) { + const topics = data.ListTopicsResponse.ListTopicsResult.Topics.member; + for (let topic of topics) { let topicArn = topic.TopicArn as string; let topicName = topicArn.split(':')[5]; @@ -102,22 +98,19 @@ export class AwsSns implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - await awsConfigCredentials.call(this); - const sns = new SNS(); - for (let i = 0; i < items.length; i++) { - const params = { - TopicArn: this.getNodeParameter('topic', i) as string, - Subject: this.getNodeParameter('subject', i) as string, - Message: this.getNodeParameter('message', i) as string, - }; + const params = [ + 'TopicArn=' + this.getNodeParameter('topic', i) as string, + 'Subject=' + this.getNodeParameter('subject', i) as string, + 'Message=' + this.getNodeParameter('message', i) as string, + ]; try { - var responseData = await sns.publish(params).promise(); + var responseData = await awsApiRequestSOAP.call(this, 'sns', 'GET', '/?Action=Publish&' + params.join('&')); } catch (err) { throw new Error(`AWS Error: ${err}`); } - returnData.push({MessageId: responseData.MessageId} as IDataObject); + returnData.push({MessageId: responseData.PublishResponse.PublishResult.MessageId} as IDataObject); } return [this.helpers.returnJsonArray(returnData)]; diff --git a/packages/nodes-base/nodes/Aws/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/GenericFunctions.ts index 30b3f2f94..cf5f7e0af 100644 --- a/packages/nodes-base/nodes/Aws/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/GenericFunctions.ts @@ -4,27 +4,12 @@ import { ILoadOptionsFunctions, } from 'n8n-core'; -import { config } from 'aws-sdk'; import { OptionsWithUri } from 'request'; import { sign } from 'aws4'; - -export async function awsConfigCredentials(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions): Promise { - const credentials = this.getCredentials('aws'); - - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } - - config.update({ - region: `${credentials.region}`, - accessKeyId: `${credentials.accessKeyId}`, - secretAccessKey: `${credentials.secretAccessKey}`, - }); -} +import { parseString } from 'xml2js'; export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('aws'); - if (credentials === undefined) { throw new Error('No credentials got returned!'); } @@ -42,9 +27,8 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I body: signOpts.body, }; - let response: string try { - response = await this.helpers.request!(options); + return await this.helpers.request!(options); } catch (error) { console.error(error); @@ -57,12 +41,35 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I } } - throw errorMessage; + if (errorMessage !== undefined) { + throw errorMessage; + } + throw error.response.body; } +} + +export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any + const response = await awsApiRequest.call(this, service, method, path, body, headers); try { return JSON.parse(response); } catch (e) { return response } } + +export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise { // tslint:disable-line:no-any + const response = await awsApiRequest.call(this, service, method, path, body, headers); + try { + return await new Promise((resolve, reject) => { + parseString(response, { explicitArray: false }, (err, data) => { + if (err) { + return reject(err); + } + resolve(data); + }); + }); + } catch (e) { + return response + } +} diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 4ee7ae8d6..fa6a8a55e 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -128,7 +128,6 @@ }, "dependencies": { "aws4": "^1.8.0", - "aws-sdk": "^2.543.0", "basic-auth": "^2.0.1", "cron": "^1.6.0", "glob-promise": "^3.4.0", From 087199798c6ac169109f9b5665a1bddec7e22586 Mon Sep 17 00:00:00 2001 From: Matheus Cansian Date: Tue, 15 Oct 2019 14:24:45 -0300 Subject: [PATCH 10/10] Add operation field to Aws nodes --- .../nodes-base/nodes/Aws/AwsLambda.node.ts | 42 +++++++++++++++++++ packages/nodes-base/nodes/Aws/AwsSns.node.ts | 35 ++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts index 312316a7d..589f31043 100644 --- a/packages/nodes-base/nodes/Aws/AwsLambda.node.ts +++ b/packages/nodes-base/nodes/Aws/AwsLambda.node.ts @@ -32,6 +32,20 @@ export class AwsLambda implements INodeType { } ], properties: [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + options: [ + { + name: 'Invoke', + value: 'invoke', + description: 'Invoke a function', + }, + ], + default: 'invoke', + description: 'The operation to perform.', + }, { displayName: 'Function', name: 'function', @@ -39,6 +53,13 @@ export class AwsLambda implements INodeType { typeOptions: { loadOptionsMethod: 'getFunctions', }, + displayOptions: { + show: { + operation: [ + 'invoke', + ], + }, + }, options: [], default: '', required: true, @@ -48,6 +69,13 @@ export class AwsLambda implements INodeType { displayName: 'Qualifier', name: 'qualifier', type: 'string', + displayOptions: { + show: { + operation: [ + 'invoke', + ], + }, + }, required: true, default: '$LATEST', description: 'Specify a version or alias to invoke a published version of the function', @@ -68,6 +96,13 @@ export class AwsLambda implements INodeType { description: 'Invoke the function and immediately continue the workflow', }, ], + displayOptions: { + show: { + operation: [ + 'invoke', + ], + }, + }, default: 'RequestResponse', description: 'Specify if the workflow should wait for the function to return the results', }, @@ -75,6 +110,13 @@ export class AwsLambda implements INodeType { displayName: 'JSON Input', name: 'payload', type: 'string', + displayOptions: { + show: { + operation: [ + 'invoke', + ], + }, + }, default: '', description: 'The JSON that you want to provide to your Lambda function as input', typeOptions: { diff --git a/packages/nodes-base/nodes/Aws/AwsSns.node.ts b/packages/nodes-base/nodes/Aws/AwsSns.node.ts index 7b12184b6..2cbdf9047 100644 --- a/packages/nodes-base/nodes/Aws/AwsSns.node.ts +++ b/packages/nodes-base/nodes/Aws/AwsSns.node.ts @@ -32,6 +32,20 @@ export class AwsSns implements INodeType { } ], properties: [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + options: [ + { + name: 'Publish', + value: 'publish', + description: 'Publish a message to a topic', + }, + ], + default: 'invoke', + description: 'The operation to perform.', + }, { displayName: 'Topic', name: 'topic', @@ -39,6 +53,13 @@ export class AwsSns implements INodeType { typeOptions: { loadOptionsMethod: 'getTopics', }, + displayOptions: { + show: { + operation: [ + 'publish', + ], + }, + }, options: [], default: '', required: true, @@ -48,6 +69,13 @@ export class AwsSns implements INodeType { displayName: 'Subject', name: 'subject', type: 'string', + displayOptions: { + show: { + operation: [ + 'publish', + ], + }, + }, default: '', required: true, description: 'Subject when the message is delivered to email endpoints', @@ -56,6 +84,13 @@ export class AwsSns implements INodeType { displayName: 'Message', name: 'message', type: 'string', + displayOptions: { + show: { + operation: [ + 'publish', + ], + }, + }, required: true, typeOptions: { alwaysOpenEditWindow: true,