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: 'signaufApi',
20
- required: true,
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-signauf",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "n8n community node for Signauf — submit approval requests and wait for human decisions",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",