diff --git a/packages/nodes-base/credentials/CopperApi.credentials.ts b/packages/nodes-base/credentials/CopperApi.credentials.ts index 12d2f75096..ea3105054d 100644 --- a/packages/nodes-base/credentials/CopperApi.credentials.ts +++ b/packages/nodes-base/credentials/CopperApi.credentials.ts @@ -21,11 +21,5 @@ export class CopperApi implements ICredentialType { type: 'string' as NodePropertyTypes, default: '', }, - { - displayName: 'Secret', - name: 'secret', - type: 'string' as NodePropertyTypes, - default: '', - }, ]; } diff --git a/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts b/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts index bb16ca6834..2c95c25ebf 100644 --- a/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts +++ b/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts @@ -12,12 +12,13 @@ import { import { copperApiRequest, + getAutomaticSecret, } from './GenericFunctions'; export class CopperTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Copper Trigger', - name: 'copper', + name: 'copperTrigger', icon: 'file:copper.png', group: ['trigger'], version: 1, @@ -50,28 +51,32 @@ export class CopperTrigger implements INodeType { required: true, default: '', options: [ - { - name: 'Lead', - value: 'lead', - }, - { - name: 'Person', - value: 'person', - }, { name: 'Company', value: 'company', }, + { + name: 'Lead', + value: 'lead', + }, { name: 'Opportunity', value: 'opportunity', }, + { + name: 'Person', + value: 'person', + }, { name: 'Project', value: 'project', }, + { + name: 'Task', + value: 'task', + }, ], - description: 'The resource is gonna fire the event', + description: 'The resource which will fire the event.', }, { displayName: 'Event', @@ -80,6 +85,11 @@ export class CopperTrigger implements INodeType { required: true, default: '', options: [ + { + name: 'Delete', + value: 'delete', + description: 'An existing record is removed', + }, { name: 'New', value: 'new', @@ -90,13 +100,8 @@ export class CopperTrigger implements INodeType { value: 'update', description: 'Any field in the existing entity record is changed', }, - { - name: 'Delete', - value: 'delete', - description: 'An existing record is removed', - }, ], - description: 'The resource is gonna fire the event', + description: 'The event to listen to.', }, ], }; @@ -112,7 +117,7 @@ export class CopperTrigger implements INodeType { try { await copperApiRequest.call(this, 'GET', endpoint); } catch (err) { - return false + return false; } return true; }, @@ -125,8 +130,14 @@ export class CopperTrigger implements INodeType { const body: IDataObject = { target: webhookUrl, type: resource, - event: event, + event, }; + + const credentials = this.getCredentials('copperApi'); + body.secret = { + secret: getAutomaticSecret(credentials!), + }; + const { id } = await copperApiRequest.call(this, 'POST', endpoint, body); webhookData.webhookId = id; return true; @@ -148,11 +159,12 @@ export class CopperTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { const credentials = this.getCredentials('copperApi'); const req = this.getRequestObject(); - if (credentials!.secret) { - if (req.body.secret !== credentials!.secret) { - return {}; - }; + + // Check if the supplied secret matches. If not ignore request. + if (req.body.secret !== getAutomaticSecret(credentials!)) { + return {}; } + return { workflowData: [ this.helpers.returnJsonArray(req.body), diff --git a/packages/nodes-base/nodes/Copper/GenericFunctions.ts b/packages/nodes-base/nodes/Copper/GenericFunctions.ts index 48222181f4..31bd1379c2 100644 --- a/packages/nodes-base/nodes/Copper/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Copper/GenericFunctions.ts @@ -1,4 +1,6 @@ +import { createHash } from 'crypto'; import { OptionsWithUri } from 'request'; + import { IExecuteFunctions, IExecuteSingleFunctions, @@ -6,18 +8,17 @@ import { ILoadOptionsFunctions, IWebhookFunctions, } from 'n8n-core'; -import { IDataObject } from 'n8n-workflow'; +import { + ICredentialDataDecryptedObject, + IDataObject, +} from 'n8n-workflow'; export async function copperApiRequest(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('copperApi'); if (credentials === undefined) { throw new Error('No credentials got returned!'); } - if (credentials.secret) { - body.secret = { - secret: credentials.secret as string, - }; - }; + let options: OptionsWithUri = { headers: { 'X-PW-AccessToken': credentials.apiKey, @@ -39,6 +40,24 @@ export async function copperApiRequest(this: IHookFunctions | IExecuteFunctions try { return await this.helpers.request!(options); } catch (error) { - throw new Error('Copper Error: ' + error.message); + let errorMessage = error.message; + if (error.response.body && error.response.body.message) { + errorMessage = error.response.body.message; + } + + throw new Error('Copper Error: ' + errorMessage); } } + + +/** + * Creates a secret from the credentials + * + * @export + * @param {ICredentialDataDecryptedObject} credentials + * @returns + */ +export function getAutomaticSecret(credentials: ICredentialDataDecryptedObject) { + const data = `${credentials.email},${credentials.apiKey}`; + return createHash('md5').update(data).digest("hex"); +}