Skip to content

Commit 03a7984

Browse files
Zie619claude
andcommitted
feat(n8n-node): v0.4.2 — self-contained TruseraWebhook with direct HTML serving
TruseraWebhook is now a single-node solution that fetches workflows, scans them, and serves the HTML dashboard directly via getResponseObject(). Includes webhookId default for clean /webhook/trusera URL path. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 91ed337 commit 03a7984

File tree

2 files changed

+82
-15
lines changed

2 files changed

+82
-15
lines changed

n8n-node/nodes/TruseraWebhook/TruseraWebhook.node.ts

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,31 @@ import type {
55
INodeTypeDescription,
66
} from 'n8n-workflow';
77

8+
import { scanWorkflows } from '../../lib/scanner';
9+
import { generateDashboardHtml } from '../../lib/dashboardHtml';
10+
811
export class TruseraWebhook implements INodeType {
912
description: INodeTypeDescription = {
1013
displayName: 'Trusera Webhook',
1114
name: 'truseraWebhook',
1215
icon: 'file:trusera.svg',
1316
group: ['trigger'],
1417
version: 1,
15-
subtitle: 'AI Security Trigger',
18+
subtitle: 'AI Security Dashboard',
1619
description:
17-
'Pre-configured webhook trigger for the Trusera AI-BOM dashboard. Connect to a Trusera Dashboard node for a one-click security dashboard.',
20+
'One-node security dashboard — add n8n API credentials, activate, and visit /webhook/trusera to see your AI-BOM report.',
1821
defaults: {
1922
name: 'Trusera Webhook',
20-
},
23+
webhookId: 'trusera-ai-bom',
24+
} as INodeTypeDescription['defaults'],
2125
inputs: [],
2226
outputs: ['main'],
27+
credentials: [
28+
{
29+
name: 'truseraApi',
30+
required: true,
31+
},
32+
],
2333
webhooks: [
2434
{
2535
name: 'default',
@@ -29,22 +39,79 @@ export class TruseraWebhook implements INodeType {
2939
isFullPath: true,
3040
},
3141
],
32-
properties: [],
42+
properties: [
43+
{
44+
displayName: 'Dashboard Password',
45+
name: 'password',
46+
type: 'string',
47+
typeOptions: { password: true },
48+
default: '',
49+
description:
50+
'Optional. If set, the dashboard is AES-256-GCM encrypted and visitors must enter this password to view it.',
51+
},
52+
],
3353
};
3454

3555
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
36-
const req = this.getRequestObject();
56+
const res = this.getResponseObject();
57+
58+
try {
59+
const creds = await this.getCredentials('truseraApi');
60+
const baseUrl = ((creds.baseUrl as string) || 'http://localhost:5678').replace(/\/$/, '');
61+
const apiKey = creds.apiKey as string;
62+
const password = this.getNodeParameter('password', '') as string;
63+
64+
// Fetch all workflows via n8n REST API (paginated)
65+
const allWorkflows: Array<Record<string, unknown>> = [];
66+
let cursor: string | null = null;
67+
do {
68+
const url =
69+
`${baseUrl}/api/v1/workflows?limit=100` +
70+
(cursor ? `&cursor=${cursor}` : '');
71+
const resp = await fetch(url, {
72+
headers: {
73+
'X-N8N-API-KEY': apiKey,
74+
'Accept': 'application/json',
75+
},
76+
});
77+
if (!resp.ok) {
78+
throw new Error(`n8n API error: ${resp.status} ${await resp.text()}`);
79+
}
80+
const data = (await resp.json()) as {
81+
data: Array<Record<string, unknown>>;
82+
nextCursor?: string;
83+
};
84+
allWorkflows.push(...data.data);
85+
cursor = data.nextCursor ?? null;
86+
} while (cursor);
87+
88+
// Scan all workflows
89+
const workflows = allWorkflows.map((wf) => ({
90+
data: wf,
91+
filePath: (wf.name as string) || (wf.id as string) || 'unknown',
92+
}));
93+
const scanResult = scanWorkflows(workflows);
94+
95+
// Generate HTML dashboard
96+
const html = generateDashboardHtml(scanResult, password || undefined);
97+
98+
// Serve HTML directly
99+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
100+
res.status(200).end(html);
101+
} catch (err) {
102+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
103+
res.status(500).end(
104+
`<!DOCTYPE html><html><body style="font-family:sans-serif;padding:40px">` +
105+
`<h1>Trusera Dashboard Error</h1>` +
106+
`<pre style="color:red">${(err as Error).message}</pre>` +
107+
`</body></html>`,
108+
);
109+
}
110+
37111
return {
112+
noWebhookResponse: true,
38113
workflowData: [
39-
[
40-
{
41-
json: {
42-
headers: req.headers as Record<string, unknown>,
43-
params: req.query as Record<string, unknown>,
44-
timestamp: new Date().toISOString(),
45-
},
46-
},
47-
],
114+
[{ json: { served: true, timestamp: new Date().toISOString() } }],
48115
],
49116
};
50117
}

n8n-node/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "n8n-nodes-trusera",
3-
"version": "0.3.2",
3+
"version": "0.4.2",
44
"description": "n8n community node to scan workflows for AI security risks using Trusera AI-BOM",
55
"keywords": [
66
"n8n-community-node-package",

0 commit comments

Comments
 (0)