@limetech/n8n-nodes-lime 0.3.6 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/credentials/LimeCrmApi.credentials.ts +13 -0
  3. package/dist/credentials/LimeCrmApi.credentials.js +12 -0
  4. package/dist/credentials/LimeCrmApi.credentials.js.map +1 -1
  5. package/dist/nodes/lime-crm/LimeCrmTrigger.node.js +17 -2
  6. package/dist/nodes/lime-crm/LimeCrmTrigger.node.js.map +1 -1
  7. package/dist/nodes/lime-crm/commons/hmac.d.ts +1 -0
  8. package/dist/nodes/lime-crm/commons/hmac.js +11 -0
  9. package/dist/nodes/lime-crm/commons/hmac.js.map +1 -0
  10. package/dist/nodes/lime-crm/commons/webhook.d.ts +3 -0
  11. package/dist/nodes/lime-crm/commons/webhook.js.map +1 -1
  12. package/dist/nodes/lime-crm/resources/erpConnector/index.d.ts +2 -2
  13. package/dist/nodes/lime-crm/resources/limeObject/index.js +6 -6
  14. package/dist/nodes/lime-crm/resources/limeObject/index.js.map +1 -1
  15. package/dist/nodes/lime-crm/resources/limeObject/operations/fetchMany.operation.d.ts +9 -0
  16. package/dist/nodes/lime-crm/resources/limeObject/operations/fetchMany.operation.js +103 -0
  17. package/dist/nodes/lime-crm/resources/limeObject/operations/fetchMany.operation.js.map +1 -0
  18. package/dist/nodes/lime-crm/resources/limeType/index.d.ts +3 -3
  19. package/dist/nodes/lime-crm/transport/index.d.ts +1 -1
  20. package/dist/nodes/lime-crm/transport/index.js +2 -2
  21. package/dist/nodes/lime-crm/transport/index.js.map +1 -1
  22. package/dist/nodes/lime-crm/transport/limeobjects.d.ts +1 -1
  23. package/dist/nodes/lime-crm/transport/limeobjects.js +5 -3
  24. package/dist/nodes/lime-crm/transport/limeobjects.js.map +1 -1
  25. package/dist/nodes/lime-crm/transport/webhooks.d.ts +2 -1
  26. package/dist/nodes/lime-crm/transport/webhooks.js +1 -0
  27. package/dist/nodes/lime-crm/transport/webhooks.js.map +1 -1
  28. package/dist/package.json +2 -1
  29. package/dist/tsconfig.tsbuildinfo +1 -1
  30. package/nodes/lime-crm/LimeCrmTrigger.node.ts +29 -3
  31. package/nodes/lime-crm/commons/hmac.ts +13 -0
  32. package/nodes/lime-crm/commons/webhook.ts +4 -0
  33. package/nodes/lime-crm/resources/limeObject/index.ts +6 -6
  34. package/nodes/lime-crm/resources/limeObject/operations/{search.operation.ts → fetchMany.operation.ts} +11 -11
  35. package/nodes/lime-crm/transport/index.ts +1 -1
  36. package/nodes/lime-crm/transport/limeobjects.ts +8 -6
  37. package/nodes/lime-crm/transport/webhooks.ts +3 -1
  38. package/package.json +2 -1
@@ -19,6 +19,8 @@ import {
19
19
  listSubscriptionsWithExistingData,
20
20
  } from './transport';
21
21
 
22
+ import { verifyHmac } from './commons/hmac';
23
+
22
24
  export class LimeCrmTrigger implements INodeType {
23
25
  description: INodeTypeDescription = {
24
26
  displayName: 'Lime CRM Trigger',
@@ -174,9 +176,17 @@ export class LimeCrmTrigger implements INodeType {
174
176
  }
175
177
 
176
178
  if (existingSubscriptionResponse.data.length === 0) {
179
+ const credentials = await this.getCredentials(
180
+ LIME_CRM_API_CREDENTIAL_KEY
181
+ );
182
+ const webhookCreateData = {
183
+ ...webhook,
184
+ secret: credentials.webhookSecret as string,
185
+ };
186
+
177
187
  const createSubscriptionResponse = await createSubscription(
178
188
  this,
179
- webhook
189
+ webhookCreateData
180
190
  );
181
191
 
182
192
  if (!createSubscriptionResponse.success) {
@@ -238,7 +248,24 @@ export class LimeCrmTrigger implements INodeType {
238
248
  Logger.info('Webhook received. Starting webhook processing...', {
239
249
  ...webhook.context,
240
250
  });
251
+ const credentials = await this.getCredentials(
252
+ LIME_CRM_API_CREDENTIAL_KEY
253
+ );
254
+ const webhookSecret = credentials.webhookSecret as string;
255
+ const requestObject = this.getRequestObject();
256
+ const headerData = this.getHeaderData();
241
257
  const bodyData = this.getBodyData();
258
+ const limeSignature = headerData['x-lime-signature'] as string;
259
+
260
+ if (
261
+ (webhookSecret || limeSignature) &&
262
+ !verifyHmac(webhookSecret, requestObject.rawBody, limeSignature)
263
+ ) {
264
+ throw new NodeOperationError(
265
+ this.getNode(),
266
+ 'Webhook authentication failed, secret keys do not match!'
267
+ );
268
+ }
242
269
 
243
270
  if (!bodyData || !bodyData.event || !bodyData.body) {
244
271
  Logger.warn('Webhook data is invalid. Missing event or body', {
@@ -251,10 +278,9 @@ export class LimeCrmTrigger implements INodeType {
251
278
  }
252
279
 
253
280
  const returnData: IDataObject[] = [];
254
-
255
281
  returnData.push({
256
282
  body: bodyData,
257
- headers: this.getHeaderData(),
283
+ headers: headerData,
258
284
  query: this.getQueryData(),
259
285
  });
260
286
 
@@ -0,0 +1,13 @@
1
+ import { createHmac } from 'node:crypto';
2
+
3
+ function _generateHmac(key: string, data: Buffer): string {
4
+ return 'sha256=' + createHmac('sha256', key).update(data).digest('hex');
5
+ }
6
+
7
+ export function verifyHmac(
8
+ key: string,
9
+ data: Buffer,
10
+ comparedHmac: string
11
+ ): boolean {
12
+ return _generateHmac(key, data) === comparedHmac;
13
+ }
@@ -17,6 +17,10 @@ export interface Webhook {
17
17
  name: string;
18
18
  }
19
19
 
20
+ export interface CreateWebhook extends Webhook {
21
+ secret?: string;
22
+ }
23
+
20
24
  function _getEvents(hookData: WebhookFunctions): string[] {
21
25
  const eventData = hookData.getNodeParameter('events', []) as {
22
26
  event: Array<{
@@ -8,7 +8,7 @@ import * as create from './operations/create.operation';
8
8
  import * as get from './operations/get.operation';
9
9
  import * as update from './operations/update.operation';
10
10
  import * as delete_ from './operations/delete.operation';
11
- import * as search from './operations/search.operation';
11
+ import * as fetchMany from './operations/fetchMany.operation';
12
12
 
13
13
  import { LIMEOBJECT_RESOURCE } from '../../commons';
14
14
 
@@ -28,16 +28,16 @@ export const limeObjectFields: INodeProperties[] = [
28
28
  get.description,
29
29
  update.description,
30
30
  delete_.description,
31
- search.description,
31
+ fetchMany.description,
32
32
  ],
33
- default: 'search',
33
+ default: 'fetchMany',
34
34
  },
35
35
 
36
36
  ...create.properties,
37
37
  ...get.properties,
38
38
  ...update.properties,
39
39
  ...delete_.properties,
40
- ...search.properties,
40
+ ...fetchMany.properties,
41
41
  ];
42
42
 
43
43
  export async function limeObjectOperations(
@@ -56,8 +56,8 @@ export async function limeObjectOperations(
56
56
  if (operation === 'delete') {
57
57
  return await delete_.execute.call(this, i);
58
58
  }
59
- if (operation === 'search') {
60
- return await search.execute.call(this, i);
59
+ if (operation === 'fetchMany') {
60
+ return await fetchMany.execute.call(this, i);
61
61
  }
62
62
 
63
63
  return null;
@@ -1,12 +1,12 @@
1
1
  import { IExecuteFunctions, INodeProperties } from 'n8n-workflow';
2
- import { searchLimeObject } from '../../../transport';
2
+ import { fetchManyLimeObjects } from '../../../transport';
3
3
  import { LIMEOBJECT_RESOURCE } from '../../../commons';
4
4
 
5
5
  export const description = {
6
- name: 'Search',
7
- value: 'search',
8
- description: 'Search for objects',
9
- action: 'Search for objects',
6
+ name: 'Fetch many',
7
+ value: 'fetchMany',
8
+ description: 'Fetch many Lime objects',
9
+ action: 'Fetch many objects',
10
10
  };
11
11
 
12
12
  export const properties: INodeProperties[] = [
@@ -23,7 +23,7 @@ export const properties: INodeProperties[] = [
23
23
  displayOptions: {
24
24
  show: {
25
25
  resource: [LIMEOBJECT_RESOURCE],
26
- operation: ['search'],
26
+ operation: ['fetchMany'],
27
27
  },
28
28
  },
29
29
  },
@@ -36,7 +36,7 @@ export const properties: INodeProperties[] = [
36
36
  displayOptions: {
37
37
  show: {
38
38
  resource: [LIMEOBJECT_RESOURCE],
39
- operation: ['search'],
39
+ operation: ['fetchMany'],
40
40
  },
41
41
  },
42
42
  },
@@ -54,7 +54,7 @@ export const properties: INodeProperties[] = [
54
54
  displayOptions: {
55
55
  show: {
56
56
  resource: [LIMEOBJECT_RESOURCE],
57
- operation: ['search'],
57
+ operation: ['fetchMany'],
58
58
  },
59
59
  },
60
60
  },
@@ -70,7 +70,7 @@ export const properties: INodeProperties[] = [
70
70
  displayOptions: {
71
71
  show: {
72
72
  resource: [LIMEOBJECT_RESOURCE],
73
- operation: ['search'],
73
+ operation: ['fetchMany'],
74
74
  },
75
75
  },
76
76
  },
@@ -86,7 +86,7 @@ export const properties: INodeProperties[] = [
86
86
  displayOptions: {
87
87
  show: {
88
88
  resource: [LIMEOBJECT_RESOURCE],
89
- operation: ['search'],
89
+ operation: ['fetchMany'],
90
90
  },
91
91
  },
92
92
  },
@@ -100,7 +100,7 @@ export async function execute(this: IExecuteFunctions, i: number) {
100
100
  const offset = this.getNodeParameter('offset', i, 0) as number;
101
101
  const options = this.getNodeParameter('options', i, {});
102
102
 
103
- return await searchLimeObject(
103
+ return await fetchManyLimeObjects(
104
104
  this,
105
105
  limeType,
106
106
  searchField,
@@ -11,7 +11,7 @@ export {
11
11
  deleteLimeObject,
12
12
  updateLimeObject,
13
13
  getLimeObject,
14
- searchLimeObject,
14
+ fetchManyLimeObjects,
15
15
  } from './limeobjects';
16
16
  export { startCreateOrUpdateObjectsTask } from './erpConnector';
17
17
  export { callLimeApi } from './commons';
@@ -4,7 +4,7 @@ import { NodeResponse } from '../../nodeResponse';
4
4
 
5
5
  const LIMEOBJECT_URL = '/api/v1/limeobject/';
6
6
 
7
- interface SearchLimeobjectApiResponse {
7
+ interface FetchManyLimeObjectsApiResponse {
8
8
  _embedded: {
9
9
  limeobjects: Array<object>;
10
10
  };
@@ -103,7 +103,7 @@ async function _searchLimeObjectWithLimit(
103
103
  limit: number,
104
104
  offset: number,
105
105
  qs: IDataObject
106
- ): Promise<NodeResponse<SearchLimeobjectApiResponse>> {
106
+ ): Promise<NodeResponse<FetchManyLimeObjectsApiResponse>> {
107
107
  const returnData = [];
108
108
  let hasMoreData = true;
109
109
  let currentOffset = Math.max(0, offset);
@@ -113,7 +113,7 @@ async function _searchLimeObjectWithLimit(
113
113
  qs._limit = Math.min(limit, pageLimit);
114
114
  qs._offset = currentOffset;
115
115
 
116
- const response = await callLimeApi<SearchLimeobjectApiResponse>(
116
+ const response = await callLimeApi<FetchManyLimeObjectsApiResponse>(
117
117
  nodeContext,
118
118
  'GET',
119
119
  url,
@@ -143,7 +143,7 @@ async function _searchLimeObjectWithLimit(
143
143
  };
144
144
  }
145
145
 
146
- export async function searchLimeObject(
146
+ export async function fetchManyLimeObjects(
147
147
  nodeContext: IAllExecuteFunctions,
148
148
  limeType: string,
149
149
  searchField: string,
@@ -169,7 +169,7 @@ export async function searchLimeObject(
169
169
  qs
170
170
  );
171
171
  } else {
172
- response = await callLimeApi<SearchLimeobjectApiResponse>(
172
+ response = await callLimeApi<FetchManyLimeObjectsApiResponse>(
173
173
  nodeContext,
174
174
  'GET',
175
175
  url,
@@ -186,7 +186,9 @@ export async function searchLimeObject(
186
186
  };
187
187
  }
188
188
  return {
189
- ...response,
189
+ success: response.success,
190
+ error: response.error,
191
+ status: response.status,
190
192
  metadata: {
191
193
  ...response.metadata,
192
194
  limeType: limeType,
@@ -2,6 +2,7 @@ import { Webhook } from '../commons';
2
2
  import { callLimeApi } from '.';
3
3
  import { IAllExecuteFunctions } from 'n8n-workflow';
4
4
  import { NodeResponse } from '../../nodeResponse';
5
+ import { CreateWebhook } from '../commons/webhook';
5
6
 
6
7
  const SUBSCRIPTION_URL = 'api/v1/subscription/';
7
8
 
@@ -39,13 +40,14 @@ export async function listSubscriptionsWithExistingData(
39
40
 
40
41
  export async function createSubscription(
41
42
  nodeContext: IAllExecuteFunctions,
42
- webhook: Webhook
43
+ webhook: CreateWebhook
43
44
  ): Promise<NodeResponse<ApiResponseWebhook>> {
44
45
  return await callLimeApi(nodeContext, 'POST', SUBSCRIPTION_URL, {
45
46
  body: {
46
47
  events: webhook.events,
47
48
  target_url: webhook.url,
48
49
  name: webhook.name,
50
+ secret: webhook.secret,
49
51
  },
50
52
  });
51
53
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@limetech/n8n-nodes-lime",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "n8n node to connect to Lime CRM",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -30,6 +30,7 @@
30
30
  ],
31
31
  "nodes": [
32
32
  "dist/nodes/lime-crm/LimeCrmNode.node.js",
33
+ "dist/nodes/lime-crm/LimeCrmTrigger.node.js",
33
34
  "dist/nodes/fortnox/Fortnox.node.js",
34
35
  "dist/nodes/fortnox/FortnoxTrigger.node.js"
35
36
  ]