n8n-nodes-signauf 0.1.2 → 0.1.4
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.
|
@@ -15,6 +15,14 @@ class SignaufApi {
|
|
|
15
15
|
default: '',
|
|
16
16
|
required: true,
|
|
17
17
|
},
|
|
18
|
+
{
|
|
19
|
+
displayName: 'Webhook Secret',
|
|
20
|
+
name: 'webhookSecret',
|
|
21
|
+
type: 'string',
|
|
22
|
+
typeOptions: { password: true },
|
|
23
|
+
default: '',
|
|
24
|
+
description: 'Found in Signauf → Settings → Webhooks. Used to verify that callbacks are genuinely from Signauf.',
|
|
25
|
+
},
|
|
18
26
|
{
|
|
19
27
|
displayName: 'Base URL',
|
|
20
28
|
name: 'baseUrl',
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
1
|
+
import { IExecuteFunctions, IHookFunctions, INodeExecutionData, INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from 'n8n-workflow';
|
|
2
2
|
export declare class Signauf implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
|
+
webhookMethods: {
|
|
5
|
+
default: {
|
|
6
|
+
checkExists(this: IHookFunctions): Promise<boolean>;
|
|
7
|
+
create(this: IHookFunctions): Promise<boolean>;
|
|
8
|
+
delete(this: IHookFunctions): Promise<boolean>;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
4
12
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
13
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Signauf = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
4
5
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
6
|
class Signauf {
|
|
6
7
|
constructor() {
|
|
@@ -14,10 +15,13 @@ class Signauf {
|
|
|
14
15
|
defaults: { name: 'Signauf' },
|
|
15
16
|
inputs: ['main'],
|
|
16
17
|
outputs: ['main'],
|
|
17
|
-
credentials: [
|
|
18
|
+
credentials: [{ name: 'signaufApi', required: true }],
|
|
19
|
+
webhooks: [
|
|
18
20
|
{
|
|
19
|
-
name: '
|
|
20
|
-
|
|
21
|
+
name: 'default',
|
|
22
|
+
httpMethod: 'POST',
|
|
23
|
+
responseMode: 'lastNode',
|
|
24
|
+
path: 'webhook',
|
|
21
25
|
},
|
|
22
26
|
],
|
|
23
27
|
properties: [
|
|
@@ -36,7 +40,6 @@ class Signauf {
|
|
|
36
40
|
],
|
|
37
41
|
default: 'submitForApproval',
|
|
38
42
|
},
|
|
39
|
-
// Submit for Approval fields
|
|
40
43
|
{
|
|
41
44
|
displayName: 'Form ID',
|
|
42
45
|
name: 'templateId',
|
|
@@ -57,6 +60,39 @@ class Signauf {
|
|
|
57
60
|
},
|
|
58
61
|
],
|
|
59
62
|
};
|
|
63
|
+
this.webhookMethods = {
|
|
64
|
+
default: {
|
|
65
|
+
async checkExists() {
|
|
66
|
+
return false;
|
|
67
|
+
},
|
|
68
|
+
async create() {
|
|
69
|
+
return true;
|
|
70
|
+
},
|
|
71
|
+
async delete() {
|
|
72
|
+
return true;
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async webhook() {
|
|
78
|
+
var _a;
|
|
79
|
+
const req = this.getRequestObject();
|
|
80
|
+
const body = this.getBodyData();
|
|
81
|
+
const credentials = await this.getCredentials('signaufApi');
|
|
82
|
+
const secret = credentials.webhookSecret;
|
|
83
|
+
if (secret) {
|
|
84
|
+
const signature = (_a = req.headers['x-signauf-signature']) !== null && _a !== void 0 ? _a : '';
|
|
85
|
+
const bodyStr = JSON.stringify(body);
|
|
86
|
+
const expected = `sha256=${(0, crypto_1.createHmac)('sha256', secret).update(bodyStr).digest('hex')}`;
|
|
87
|
+
if (signature !== expected) {
|
|
88
|
+
const resp = this.getResponseObject();
|
|
89
|
+
resp.status(401).json({ error: 'Invalid signature' });
|
|
90
|
+
return { noWebhookResponse: true };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
workflowData: [this.helpers.returnJsonArray([body])],
|
|
95
|
+
};
|
|
60
96
|
}
|
|
61
97
|
async execute() {
|
|
62
98
|
var _a;
|
|
@@ -75,7 +111,6 @@ class Signauf {
|
|
|
75
111
|
catch {
|
|
76
112
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Payload must be valid JSON', { itemIndex: i });
|
|
77
113
|
}
|
|
78
|
-
// Grab n8n's resume URL for this execution — Signauf will POST here on decision
|
|
79
114
|
const resumeUrl = this.evaluateExpression('{{ $execution.resumeUrl }}', i);
|
|
80
115
|
if (!resumeUrl) {
|
|
81
116
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Could not get execution resume URL. Make sure your n8n instance has a webhook base URL configured.', { itemIndex: i });
|
|
@@ -87,23 +122,14 @@ class Signauf {
|
|
|
87
122
|
Authorization: `Bearer ${apiKey}`,
|
|
88
123
|
'Content-Type': 'application/json',
|
|
89
124
|
},
|
|
90
|
-
body: {
|
|
91
|
-
templateId,
|
|
92
|
-
payload,
|
|
93
|
-
callbackUrl: resumeUrl,
|
|
94
|
-
},
|
|
125
|
+
body: { templateId, payload, callbackUrl: resumeUrl },
|
|
95
126
|
json: true,
|
|
96
127
|
});
|
|
97
128
|
returnData.push({
|
|
98
|
-
json:
|
|
99
|
-
...((_a = response.data) !== null && _a !== void 0 ? _a : response),
|
|
100
|
-
_debug: { callbackUrl: resumeUrl },
|
|
101
|
-
},
|
|
129
|
+
json: (_a = response.data) !== null && _a !== void 0 ? _a : response,
|
|
102
130
|
pairedItem: { item: i },
|
|
103
131
|
});
|
|
104
132
|
}
|
|
105
|
-
// Pause this execution — resumes automatically when Signauf POSTs to the callbackUrl
|
|
106
|
-
// The resumed execution receives the decision payload (status, comment, requestId, etc.)
|
|
107
133
|
await this.putExecutionToWait(new Date(Date.now() + 365 * 24 * 60 * 60 * 1000));
|
|
108
134
|
return [returnData];
|
|
109
135
|
}
|