n8n-nodes-elearning-magic 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -11,11 +11,10 @@ Restart n8n after install.
11
11
 
12
12
  ## Configure
13
13
  1) Add the **eLearning Magic** trigger node.
14
- 2) Set a unique **Webhook Path**. After you save/activate, the node shows copyable Test/Production URLs (like the n8n Webhook node).
15
- 3) Create an **eLearning Magic Signing Secret** credential with your secret.
16
- 4) (Optional) Set a **Node ID** and enable **Enforce Node ID Match**.
17
- 5) Copy the webhook URL from the node and paste it into the eLearning Magic app when creating a connection (use the same secret and Node ID).
18
- 6) Activate the workflow. Incoming events appear with request body, headers, query, and meta flags for signature/Node ID checks.
14
+ 2) Webhook Path auto-fills with a workflow-based value; you can leave it or change it. After you save/activate, the node shows copyable Test/Production URLs (like the n8n Webhook node).
15
+ 3) Create an **eLearning Magic Signing Secret** credential with your secret (signature is required).
16
+ 4) Copy the webhook URL from the node and paste it into the eLearning Magic app when creating a connection (use the same secret).
17
+ 5) Activate the workflow. Incoming events appear with the JSON body plus headers/query and a signature status flag.
19
18
 
20
19
  ## Headers expected
21
20
  - `X-EM-Signature`: HMAC-SHA256 of the raw body using your signing secret.
@@ -43,7 +43,6 @@ class ElearningMagicTrigger {
43
43
  httpMethod: 'POST',
44
44
  responseMode: 'onReceived',
45
45
  path: '={{$parameter["path"]}}',
46
- isFullPath: true,
47
46
  restartWebhook: true,
48
47
  },
49
48
  ],
@@ -52,57 +51,8 @@ class ElearningMagicTrigger {
52
51
  displayName: 'Webhook Path',
53
52
  name: 'path',
54
53
  type: 'string',
55
- default: 'elearning-magic',
56
- description: 'Unique path segment to receive data on (visible in the Webhook URLs panel)',
57
- },
58
- {
59
- displayName: 'Node ID (optional)',
60
- name: 'nodeId',
61
- type: 'string',
62
- default: '',
63
- description: 'If set, the trigger expects the X-EM-Node-Id header to match this value',
64
- },
65
- {
66
- displayName: 'Enforce Node ID Match',
67
- name: 'enforceNodeId',
68
- type: 'boolean',
69
- default: false,
70
- description: 'Reject requests whose X-EM-Node-Id header does not match the configured Node ID',
71
- },
72
- {
73
- displayName: 'Require Signature',
74
- name: 'requireSignature',
75
- type: 'boolean',
76
- default: true,
77
- description: 'Reject requests without a valid X-EM-Signature HMAC (SHA-256) header',
78
- },
79
- {
80
- displayName: 'Include Raw Body',
81
- name: 'includeRawBody',
82
- type: 'boolean',
83
- default: false,
84
- description: 'Attach the raw request body to the emitted item for debugging',
85
- },
86
- {
87
- displayName: 'Response Code',
88
- name: 'responseCode',
89
- type: 'number',
90
- default: 200,
91
- typeOptions: {
92
- minValue: 100,
93
- maxValue: 599,
94
- },
95
- description: 'HTTP status returned to the caller after processing',
96
- },
97
- {
98
- displayName: 'Response Body',
99
- name: 'responseBody',
100
- type: 'string',
101
- typeOptions: {
102
- rows: 3,
103
- },
104
- default: '{"received":true}',
105
- description: 'JSON string or plain text to return to the caller',
54
+ default: '={{$workflow.id}}-elearning-magic',
55
+ description: 'Unique path segment; defaults to a workflow-scoped value. Copy the Test/Production URLs after saving.',
106
56
  },
107
57
  ],
108
58
  };
@@ -110,50 +60,28 @@ class ElearningMagicTrigger {
110
60
  async webhook() {
111
61
  const req = this.getRequestObject();
112
62
  const res = this.getResponseObject();
113
- const nodeId = (this.getNodeParameter('nodeId') || '').trim();
114
- const enforceNodeId = this.getNodeParameter('enforceNodeId');
115
- const requireSignature = this.getNodeParameter('requireSignature');
116
- const includeRawBody = this.getNodeParameter('includeRawBody');
117
- const responseCode = this.getNodeParameter('responseCode');
118
- const responseBodyParam = this.getNodeParameter('responseBody');
119
63
  const credentials = await this.getCredentials('elearningMagicApi');
120
64
  const signingSecret = (credentials === null || credentials === void 0 ? void 0 : credentials.signingSecret) || '';
121
65
  const rawBody = req.rawBody !== undefined
122
66
  ? req.rawBody.toString('utf8')
123
67
  : JSON.stringify(req.body || {});
124
68
  const headerSignature = req.headers['x-em-signature'] || '';
125
- const headerNodeId = req.headers['x-em-node-id'] || '';
126
69
  let signatureValid = false;
127
70
  if (headerSignature && signingSecret) {
128
71
  const computed = computeSignature(signingSecret, rawBody);
129
72
  signatureValid = safeCompare(computed, headerSignature);
130
73
  }
131
- if (requireSignature) {
132
- if (!signingSecret) {
133
- res.status(401);
134
- return {
135
- webhookResponse: { error: 'Signing secret is not configured on this node' },
136
- };
137
- }
138
- if (!headerSignature || !signatureValid) {
139
- res.status(403);
140
- return {
141
- webhookResponse: { error: 'Invalid or missing X-EM-Signature header' },
142
- };
143
- }
144
- }
145
- let nodeIdMatched = true;
146
- if (enforceNodeId) {
147
- nodeIdMatched = !!nodeId && !!headerNodeId && nodeId === headerNodeId;
148
- if (!nodeIdMatched) {
149
- res.status(403);
150
- return {
151
- webhookResponse: { error: 'X-EM-Node-Id header did not match the configured Node ID' },
152
- };
153
- }
74
+ if (!signingSecret) {
75
+ res.status(401);
76
+ return {
77
+ webhookResponse: { error: 'Signing secret is not configured on this node' },
78
+ };
154
79
  }
155
- else if (nodeId) {
156
- nodeIdMatched = headerNodeId ? nodeId === headerNodeId : true;
80
+ if (!headerSignature || !signatureValid) {
81
+ res.status(403);
82
+ return {
83
+ webhookResponse: { error: 'Invalid or missing X-EM-Signature header' },
84
+ };
157
85
  }
158
86
  const payload = {
159
87
  json: {
@@ -162,30 +90,14 @@ class ElearningMagicTrigger {
162
90
  headers: req.headers,
163
91
  meta: {
164
92
  receivedAt: new Date().toISOString(),
165
- signatureValid: requireSignature ? signatureValid : null,
166
- nodeIdMatched,
93
+ signatureValid,
167
94
  webhookPath: req.url,
168
95
  },
169
96
  },
170
97
  };
171
- if (includeRawBody) {
172
- payload.json.rawBody = rawBody;
173
- }
174
- let responseBody = responseBodyParam;
175
- if (typeof responseBodyParam === 'string') {
176
- const trimmed = responseBodyParam.trim();
177
- if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
178
- try {
179
- responseBody = JSON.parse(trimmed);
180
- }
181
- catch {
182
- responseBody = responseBodyParam;
183
- }
184
- }
185
- }
186
- res.status(responseCode || 200);
98
+ res.status(200);
187
99
  return {
188
- webhookResponse: responseBody,
100
+ webhookResponse: { received: true },
189
101
  workflowData: [this.helpers.returnJsonArray([payload.json])],
190
102
  };
191
103
  }
@@ -0,0 +1 @@
1
+ <?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="239.09" height="241.78" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 239.09 241.78"><defs><style>.cls-1{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="0" y1="120.89" x2="239.09" y2="120.89" gradientUnits="userSpaceOnUse"><stop offset=".32" stop-color="#bf00a7"/><stop offset="1" stop-color="#5c00e9"/></linearGradient></defs><path class="cls-1" d="M.06,240.33c21.58-25.98,50.53-58.9,72.12-84.88,12.66-15.23,29.3-33.54,42.08-48.93-18.77,0-43.96,1.69-62.81,1.69,5.16-5.47,10.32-10.94,15.48-16.42,3.31-3.51,6.59-7.07,9.9-10.58,2.42-2.57,8.32-4.31,11.56-4.88,10.3-1.79,20.85-3.72,31.17-4.13,3.53-.14,6.18-.93,8.72-3.65,14.34-15.3,28.09-28.92,42.69-43.97,6.87-7.08,15.84-11.12,24.76-14.63C208.26,5,221.41,1.89,234.85.1c3.62-.48,4.47.83,4.2,4.04-.77,9.15-3,18.16-5.81,26.68-3.57,10.93-6.43,20.35-11.72,30.71-1.15,2.49-3.53,5.97-5.87,8.43-13.91,14.58-26.75,29.94-40.74,44.44-2.55,2.65-3.5,5.31-3.3,8.87.59,10.4.54,21.57-2.77,31.45-.41,1.24-.84,2.62-1.68,3.54-8.75,9.54-19,17.98-28.71,28.43-.63-20.82-1.23-40.44-1.84-60.72C91.18,159.51,41.84,203.15,1.47,241.71c-1.17.26-1.65-.2-1.42-1.38Z"/></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-elearning-magic",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "n8n community node for receiving signed payloads from the eLearning Magic SCORM wrapper",
5
5
  "keywords": [
6
6
  "n8n-community-node",
@@ -26,7 +26,7 @@
26
26
  "LICENSE"
27
27
  ],
28
28
  "scripts": {
29
- "build": "tsc",
29
+ "build": "tsc && mkdir -p dist/nodes/ElearningMagic && cp src/nodes/ElearningMagic/elearningMagic.svg dist/nodes/ElearningMagic/",
30
30
  "prepare": "npm run build"
31
31
  },
32
32
  "devDependencies": {