n8n-nodes-trusera 0.5.0 → 0.5.2
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/dist/lib/dashboardHtml.d.ts.map +1 -1
- package/dist/lib/dashboardHtml.js +15 -14
- package/dist/lib/dashboardHtml.js.map +1 -1
- package/dist/nodes/TruseraWebhook/TruseraWebhook.node.d.ts.map +1 -1
- package/dist/nodes/TruseraWebhook/TruseraWebhook.node.js +22 -3
- package/dist/nodes/TruseraWebhook/TruseraWebhook.node.js.map +1 -1
- package/nodes/TruseraWebhook/TruseraWebhook.node.ts +23 -3
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboardHtml.d.ts","sourceRoot":"","sources":["../../lib/dashboardHtml.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,
|
|
1
|
+
{"version":3,"file":"dashboardHtml.d.ts","sourceRoot":"","sources":["../../lib/dashboardHtml.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CA8wBR"}
|
|
@@ -18,7 +18,7 @@ function generateDashboardHtml(scanResult, password) {
|
|
|
18
18
|
let dataScript;
|
|
19
19
|
let decryptionScript = '';
|
|
20
20
|
let passwordFormHtml = '';
|
|
21
|
-
const remediationScript = `<script>var REMEDIATION_MAP = ${JSON.stringify(config_1.REMEDIATION_MAP)};</script>`;
|
|
21
|
+
const remediationScript = `<script>var REMEDIATION_MAP = ${JSON.stringify(config_1.REMEDIATION_MAP).replace(/<\//g, '<\\/')};</script>`;
|
|
22
22
|
if (password) {
|
|
23
23
|
const salt = (0, crypto_1.randomBytes)(16);
|
|
24
24
|
const iv = (0, crypto_1.randomBytes)(12);
|
|
@@ -71,24 +71,25 @@ async function handleLogin(e) {
|
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
SCAN_DATA = data;
|
|
74
|
-
try {
|
|
74
|
+
try {
|
|
75
|
+
sessionStorage.setItem('trusera-data', JSON.stringify(data));
|
|
76
|
+
} catch(e) {}
|
|
75
77
|
document.getElementById('login-screen').classList.add('hidden');
|
|
76
78
|
document.getElementById('dashboard').classList.remove('hidden');
|
|
77
79
|
renderDashboard();
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
async function trySessionRestore() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
SCAN_DATA = data;
|
|
83
|
+
try {
|
|
84
|
+
var raw = sessionStorage.getItem('trusera-data');
|
|
85
|
+
if (raw) {
|
|
86
|
+
SCAN_DATA = JSON.parse(raw);
|
|
86
87
|
document.getElementById('login-screen').classList.add('hidden');
|
|
87
88
|
document.getElementById('dashboard').classList.remove('hidden');
|
|
88
89
|
renderDashboard();
|
|
89
90
|
return;
|
|
90
91
|
}
|
|
91
|
-
}
|
|
92
|
+
} catch(e) {}
|
|
92
93
|
document.getElementById('login-screen').classList.remove('hidden');
|
|
93
94
|
}
|
|
94
95
|
`;
|
|
@@ -111,7 +112,7 @@ async function trySessionRestore() {
|
|
|
111
112
|
</div>`;
|
|
112
113
|
}
|
|
113
114
|
else {
|
|
114
|
-
dataScript = `<script>var SCAN_DATA = ${jsonPayload};</script>`;
|
|
115
|
+
dataScript = `<script>var SCAN_DATA = ${jsonPayload.replace(/<\//g, '<\\/')};</script>`;
|
|
115
116
|
}
|
|
116
117
|
const dashboardHiddenClass = password ? ' hidden' : '';
|
|
117
118
|
return `<!DOCTYPE html>
|
|
@@ -120,7 +121,7 @@ async function trySessionRestore() {
|
|
|
120
121
|
<meta charset="UTF-8">
|
|
121
122
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
122
123
|
<title>Trusera AI-BOM Dashboard</title>
|
|
123
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"><\/script>
|
|
124
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js" integrity="sha384-bJFOSBzPRbfMrlRk8kGnSMA3t0DqP01GYIKZO9YFi5ZjdDbeqYeAzn9iUcbnrsnk" crossorigin="anonymous"><\/script>
|
|
124
125
|
<style>
|
|
125
126
|
:root {
|
|
126
127
|
--bg: #0d1117;
|
|
@@ -693,17 +694,17 @@ function showComponentModal(idx) {
|
|
|
693
694
|
modalRow('Provider', c.provider || '-') +
|
|
694
695
|
modalRow('Model', c.modelName || '-') +
|
|
695
696
|
modalRow('Version', c.version || '-') +
|
|
696
|
-
modalRow('Severity', severityBadge(sev)) +
|
|
697
|
+
modalRow('Severity', severityBadge(sev), true) +
|
|
697
698
|
modalRow('Risk Score', String(score)) +
|
|
698
699
|
modalRow('Workflow', fp) +
|
|
699
|
-
modalRow('OWASP Categories', owaspCats) +
|
|
700
|
+
modalRow('OWASP Categories', owaspCats, true) +
|
|
700
701
|
modalRow('Source', c.source || '-') +
|
|
701
702
|
flagsHtml +
|
|
702
703
|
'</div></div>';
|
|
703
704
|
}
|
|
704
705
|
|
|
705
|
-
function modalRow(label, value) {
|
|
706
|
-
return '<div class="modal-row"><div class="modal-label">' + esc(label) + '</div><div class="modal-value">' + (
|
|
706
|
+
function modalRow(label, value, isHTML) {
|
|
707
|
+
return '<div class="modal-row"><div class="modal-label">' + esc(label) + '</div><div class="modal-value">' + (isHTML ? value : esc(value)) + '</div></div>';
|
|
707
708
|
}
|
|
708
709
|
|
|
709
710
|
function closeModal(event) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboardHtml.js","sourceRoot":"","sources":["../../lib/dashboardHtml.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAWH,
|
|
1
|
+
{"version":3,"file":"dashboardHtml.js","sourceRoot":"","sources":["../../lib/dashboardHtml.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TruseraWebhook.node.d.ts","sourceRoot":"","sources":["../../../nodes/TruseraWebhook/TruseraWebhook.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,oBAAoB,EACrB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"TruseraWebhook.node.d.ts","sourceRoot":"","sources":["../../../nodes/TruseraWebhook/TruseraWebhook.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,oBAAoB,EACrB,MAAM,cAAc,CAAC;AAkBtB,qBAAa,cAAe,YAAW,SAAS;IAC9C,WAAW,EAAE,oBAAoB,CAyC/B;IAEI,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAsEtE"}
|
|
@@ -3,6 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TruseraWebhook = void 0;
|
|
4
4
|
const scanner_1 = require("../../lib/scanner");
|
|
5
5
|
const dashboardHtml_1 = require("../../lib/dashboardHtml");
|
|
6
|
+
/**
|
|
7
|
+
* Escape HTML special characters to prevent XSS in error messages.
|
|
8
|
+
* OWASP: A03:2021 - Injection (Cross-Site Scripting)
|
|
9
|
+
*/
|
|
10
|
+
function escapeHtml(str) {
|
|
11
|
+
return str
|
|
12
|
+
.replace(/&/g, '&')
|
|
13
|
+
.replace(/</g, '<')
|
|
14
|
+
.replace(/>/g, '>')
|
|
15
|
+
.replace(/"/g, '"')
|
|
16
|
+
.replace(/'/g, ''');
|
|
17
|
+
}
|
|
6
18
|
class TruseraWebhook {
|
|
7
19
|
constructor() {
|
|
8
20
|
this.description = {
|
|
@@ -58,7 +70,7 @@ class TruseraWebhook {
|
|
|
58
70
|
let cursor = null;
|
|
59
71
|
do {
|
|
60
72
|
const url = `${baseUrl}/api/v1/workflows?limit=100` +
|
|
61
|
-
(cursor ? `&cursor=${cursor}` : '');
|
|
73
|
+
(cursor ? `&cursor=${encodeURIComponent(cursor)}` : '');
|
|
62
74
|
const resp = await fetch(url, {
|
|
63
75
|
headers: {
|
|
64
76
|
'X-N8N-API-KEY': apiKey,
|
|
@@ -80,15 +92,22 @@ class TruseraWebhook {
|
|
|
80
92
|
const scanResult = (0, scanner_1.scanWorkflows)(workflows);
|
|
81
93
|
// Generate HTML dashboard
|
|
82
94
|
const html = (0, dashboardHtml_1.generateDashboardHtml)(scanResult, password || undefined);
|
|
83
|
-
// Serve HTML directly
|
|
95
|
+
// Serve HTML directly with security headers
|
|
84
96
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
97
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
98
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
99
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
85
100
|
res.status(200).end(html);
|
|
86
101
|
}
|
|
87
102
|
catch (err) {
|
|
103
|
+
// Escape error message to prevent reflected XSS via crafted error strings
|
|
104
|
+
// OWASP: A03:2021 - Injection (Cross-Site Scripting)
|
|
88
105
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
106
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
107
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
89
108
|
res.status(500).end(`<!DOCTYPE html><html><body style="font-family:sans-serif;padding:40px">` +
|
|
90
109
|
`<h1>Trusera Dashboard Error</h1>` +
|
|
91
|
-
`<pre style="color:red">${err.message}</pre>` +
|
|
110
|
+
`<pre style="color:red">${escapeHtml(err.message)}</pre>` +
|
|
92
111
|
`</body></html>`);
|
|
93
112
|
}
|
|
94
113
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TruseraWebhook.node.js","sourceRoot":"","sources":["../../../nodes/TruseraWebhook/TruseraWebhook.node.ts"],"names":[],"mappings":";;;AAOA,+CAAkD;AAClD,2DAAgE;AAEhE,MAAa,cAAc;IAA3B;QACE,gBAAW,GAAyB;YAClC,WAAW,EAAE,iBAAiB;YAC9B,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,kBAAkB;YACxB,KAAK,EAAE,CAAC,SAAS,CAAC;YAClB,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,uBAAuB;YACjC,WAAW,EACT,wHAAwH;YAC1H,QAAQ,EAAE;gBACR,IAAI,EAAE,iBAAiB;gBACvB,SAAS,EAAE,gBAAgB;aACQ;YACrC,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,CAAC,MAAM,CAAC;YACjB,WAAW,EAAE;gBACX;oBACE,IAAI,EAAE,YAAY;oBAClB,QAAQ,EAAE,IAAI;iBACf;aACF;YACD,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,SAAS;oBACf,UAAU,EAAE,KAAK;oBACjB,YAAY,EAAE,UAAU;oBACxB,IAAI,EAAE,SAAS;oBACf,UAAU,EAAE,IAAI;iBACjB;aACF;YACD,UAAU,EAAE;gBACV;oBACE,WAAW,EAAE,oBAAoB;oBACjC,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC/B,OAAO,EAAE,EAAE;oBACX,WAAW,EACT,4GAA4G;iBAC/G;aACF;SACF,CAAC;
|
|
1
|
+
{"version":3,"file":"TruseraWebhook.node.js","sourceRoot":"","sources":["../../../nodes/TruseraWebhook/TruseraWebhook.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,19 @@ import type {
|
|
|
8
8
|
import { scanWorkflows } from '../../lib/scanner';
|
|
9
9
|
import { generateDashboardHtml } from '../../lib/dashboardHtml';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Escape HTML special characters to prevent XSS in error messages.
|
|
13
|
+
* OWASP: A03:2021 - Injection (Cross-Site Scripting)
|
|
14
|
+
*/
|
|
15
|
+
function escapeHtml(str: string): string {
|
|
16
|
+
return str
|
|
17
|
+
.replace(/&/g, '&')
|
|
18
|
+
.replace(/</g, '<')
|
|
19
|
+
.replace(/>/g, '>')
|
|
20
|
+
.replace(/"/g, '"')
|
|
21
|
+
.replace(/'/g, ''');
|
|
22
|
+
}
|
|
23
|
+
|
|
11
24
|
export class TruseraWebhook implements INodeType {
|
|
12
25
|
description: INodeTypeDescription = {
|
|
13
26
|
displayName: 'Trusera Webhook',
|
|
@@ -67,7 +80,7 @@ export class TruseraWebhook implements INodeType {
|
|
|
67
80
|
do {
|
|
68
81
|
const url =
|
|
69
82
|
`${baseUrl}/api/v1/workflows?limit=100` +
|
|
70
|
-
(cursor ? `&cursor=${cursor}` : '');
|
|
83
|
+
(cursor ? `&cursor=${encodeURIComponent(cursor)}` : '');
|
|
71
84
|
const resp = await fetch(url, {
|
|
72
85
|
headers: {
|
|
73
86
|
'X-N8N-API-KEY': apiKey,
|
|
@@ -95,15 +108,22 @@ export class TruseraWebhook implements INodeType {
|
|
|
95
108
|
// Generate HTML dashboard
|
|
96
109
|
const html = generateDashboardHtml(scanResult, password || undefined);
|
|
97
110
|
|
|
98
|
-
// Serve HTML directly
|
|
111
|
+
// Serve HTML directly with security headers
|
|
99
112
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
113
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
114
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
115
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
100
116
|
res.status(200).end(html);
|
|
101
117
|
} catch (err) {
|
|
118
|
+
// Escape error message to prevent reflected XSS via crafted error strings
|
|
119
|
+
// OWASP: A03:2021 - Injection (Cross-Site Scripting)
|
|
102
120
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
121
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
122
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
103
123
|
res.status(500).end(
|
|
104
124
|
`<!DOCTYPE html><html><body style="font-family:sans-serif;padding:40px">` +
|
|
105
125
|
`<h1>Trusera Dashboard Error</h1>` +
|
|
106
|
-
`<pre style="color:red">${(err as Error).message}</pre>` +
|
|
126
|
+
`<pre style="color:red">${escapeHtml((err as Error).message)}</pre>` +
|
|
107
127
|
`</body></html>`,
|
|
108
128
|
);
|
|
109
129
|
}
|