@limetech/n8n-nodes-lime 3.10.1 → 3.10.3
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.
- package/CHANGELOG.md +15 -0
- package/credentials/LimeFormsApi.credentials.ts +0 -18
- package/dist/credentials/LimeFormsApi.credentials.js +0 -15
- package/dist/credentials/LimeFormsApi.credentials.js.map +1 -1
- package/dist/nodes/lime-crm/transport/commons.d.ts +2 -2
- package/dist/nodes/lime-crm/transport/commons.js +8 -7
- package/dist/nodes/lime-crm/transport/commons.js.map +1 -1
- package/dist/nodes/lime-forms/LimeFormsTrigger.node.js +22 -9
- package/dist/nodes/lime-forms/LimeFormsTrigger.node.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/nodes/lime-crm/transport/commons.ts +9 -8
- package/nodes/lime-forms/LimeFormsTrigger.node.ts +51 -19
- package/package.json +1 -1
|
@@ -83,7 +83,7 @@ interface LimeAPIArguments {
|
|
|
83
83
|
[key: string]: unknown;
|
|
84
84
|
};
|
|
85
85
|
json?: boolean;
|
|
86
|
-
errorMetadata?:
|
|
86
|
+
errorMetadata?: JsonObject;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
@@ -106,7 +106,7 @@ export async function callLimeApi<T>(
|
|
|
106
106
|
const { headers: callerHeaders, ...restRequestOptions } =
|
|
107
107
|
options.requestOptions ?? {};
|
|
108
108
|
const response =
|
|
109
|
-
await nodeContext.helpers.
|
|
109
|
+
await nodeContext.helpers.httpRequestWithAuthentication.call(
|
|
110
110
|
nodeContext,
|
|
111
111
|
LIME_CRM_API_CREDENTIAL_KEY,
|
|
112
112
|
{
|
|
@@ -126,15 +126,16 @@ export async function callLimeApi<T>(
|
|
|
126
126
|
data: response,
|
|
127
127
|
};
|
|
128
128
|
} catch (error) {
|
|
129
|
-
const
|
|
129
|
+
const apiBody = error.context?.data;
|
|
130
130
|
const errorContext: WorkflowErrorContext = {
|
|
131
|
-
message: error
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
message: error.description
|
|
132
|
+
? `${error.message}. ${error.description}`
|
|
133
|
+
: error.message,
|
|
134
|
+
status: error.httpCode ?? undefined,
|
|
134
135
|
metadata: {
|
|
135
|
-
...options.requestOptions,
|
|
136
136
|
...options.errorMetadata,
|
|
137
|
-
}
|
|
137
|
+
},
|
|
138
|
+
...(apiBody != null && { error: apiBody }),
|
|
138
139
|
};
|
|
139
140
|
return handleWorkflowError(nodeContext.getNode(), errorContext, true);
|
|
140
141
|
}
|
|
@@ -22,8 +22,9 @@ import { ObservableActionType } from './types/enums/ObservableAction';
|
|
|
22
22
|
import { ObservableType } from './types/enums/ObservableType';
|
|
23
23
|
import { FORMS_API_CREDENTIALS_NAME } from '../../credentials';
|
|
24
24
|
import { getWorkflowUrl } from './utils/workflow';
|
|
25
|
-
import { verifyHmac } from '../crypto';
|
|
25
|
+
import { decryptSecret, encryptSecret, verifyHmac } from '../crypto';
|
|
26
26
|
import { handleWorkflowError } from '../errorHandling';
|
|
27
|
+
import { randomBytes } from 'node:crypto';
|
|
27
28
|
|
|
28
29
|
const FORMS_OBSERVABLE_WEBHOOK_NAME_PREFIX = 'N8N';
|
|
29
30
|
|
|
@@ -131,22 +132,26 @@ export class LimeFormsTrigger implements INodeType {
|
|
|
131
132
|
},
|
|
132
133
|
|
|
133
134
|
async create(this: IHookFunctions): Promise<boolean> {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
136
|
+
// Generate a per-webhook secret, keep an encrypted copy in the
|
|
137
|
+
// workflow static data and only ever hand the plaintext to Lime
|
|
138
|
+
// Forms. The secret is decrypted on each incoming request to
|
|
139
|
+
// validate the signature. See {@link encryptSecret}.
|
|
140
|
+
const rawSecret = randomBytes(32).toString('hex');
|
|
141
|
+
webhookData.webhookSecret = encryptSecret(rawSecret);
|
|
142
|
+
|
|
137
143
|
const data = {
|
|
138
144
|
name: `${FORMS_OBSERVABLE_WEBHOOK_NAME_PREFIX}: ${this.getNodeParameter('name')}`,
|
|
139
145
|
observableType: ObservableType.FORM,
|
|
140
146
|
observableId: this.getNodeParameter('formId'),
|
|
141
147
|
action: ObservableActionType.FORM_SUBMITTED,
|
|
142
148
|
webhookUrl: this.getNodeWebhookUrl('default'),
|
|
143
|
-
secret:
|
|
149
|
+
secret: rawSecret,
|
|
144
150
|
workflowUrl: getWorkflowUrl(
|
|
145
151
|
this.getNode(),
|
|
146
152
|
this.getWorkflow().id
|
|
147
153
|
),
|
|
148
154
|
};
|
|
149
|
-
const webhookData = this.getWorkflowStaticData('node');
|
|
150
155
|
|
|
151
156
|
try {
|
|
152
157
|
const response =
|
|
@@ -164,22 +169,41 @@ export class LimeFormsTrigger implements INodeType {
|
|
|
164
169
|
|
|
165
170
|
return true;
|
|
166
171
|
} catch (error) {
|
|
167
|
-
// 409
|
|
172
|
+
// 409 indicates a duplicate webhook already exists in Lime
|
|
173
|
+
// Forms. Its secret was set on an earlier registration and
|
|
174
|
+
// is unknown to us, so reusing it would resurrect the
|
|
175
|
+
// "signatures do not match" failures. Delete the stale
|
|
176
|
+
// webhook and recreate it with the freshly generated secret.
|
|
168
177
|
if (error?.httpCode == '409') {
|
|
169
|
-
Logger.info(
|
|
170
|
-
`Webhook ${webhookData.name} already exists in Lime Forms, retrieving existing webhook ID`,
|
|
171
|
-
{ errorResponse: error.context?.data }
|
|
172
|
-
);
|
|
173
178
|
/**
|
|
174
179
|
* Error response structure reference:
|
|
175
180
|
* @see https://github.com/n8n-io/n8n/blob/n8n%401.120.0/packages/core/src/execution-engine/node-execution-context/utils/request-helper-functions.ts#L1280
|
|
176
181
|
*/
|
|
177
182
|
const errorResponse = error.context?.data?.error;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
183
|
+
Logger.info(
|
|
184
|
+
`Webhook ${errorResponse?.name} already exists in Lime Forms, recreating it with a fresh secret`,
|
|
185
|
+
{ errorResponse: error.context?.data }
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
await new LimeFormsRequest<ObservableWebhookSimpleResource>(
|
|
189
|
+
this
|
|
190
|
+
).delete(
|
|
191
|
+
`/api/v1/observable-webhooks/${errorResponse.id}`
|
|
182
192
|
);
|
|
193
|
+
|
|
194
|
+
const response =
|
|
195
|
+
await new LimeFormsRequest<ObservableWebhookDetailedResource>(
|
|
196
|
+
this
|
|
197
|
+
).post('/api/v1/observable-webhooks', data);
|
|
198
|
+
|
|
199
|
+
if (!response.success) {
|
|
200
|
+
throw new NodeApiError(this.getNode(), {
|
|
201
|
+
message:
|
|
202
|
+
'Failed to create webhook in Lime Forms',
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
webhookData.id = response.data.id;
|
|
183
207
|
return true;
|
|
184
208
|
}
|
|
185
209
|
throw new NodeApiError(this.getNode(), {
|
|
@@ -207,7 +231,7 @@ export class LimeFormsTrigger implements INodeType {
|
|
|
207
231
|
}
|
|
208
232
|
|
|
209
233
|
delete webhookData.id;
|
|
210
|
-
delete webhookData.
|
|
234
|
+
delete webhookData.webhookSecret;
|
|
211
235
|
|
|
212
236
|
return true;
|
|
213
237
|
},
|
|
@@ -227,9 +251,17 @@ export class LimeFormsTrigger implements INodeType {
|
|
|
227
251
|
);
|
|
228
252
|
}
|
|
229
253
|
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
254
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
255
|
+
const encryptedSecret = webhookData.webhookSecret as
|
|
256
|
+
| string
|
|
257
|
+
| undefined;
|
|
258
|
+
if (!encryptedSecret) {
|
|
259
|
+
throw new NodeOperationError(
|
|
260
|
+
this.getNode(),
|
|
261
|
+
'Webhook is not registered: missing secret in static data'
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
const webhookSecret = decryptSecret(encryptedSecret);
|
|
233
265
|
const isValidSignature = verifyHmac(
|
|
234
266
|
webhookSecret,
|
|
235
267
|
Buffer.from(JSON.stringify(body)),
|