@panguard-ai/panguard-guard 0.1.0
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/agent/analyze-agent.d.ts +62 -0
- package/dist/agent/analyze-agent.d.ts.map +1 -0
- package/dist/agent/analyze-agent.js +327 -0
- package/dist/agent/analyze-agent.js.map +1 -0
- package/dist/agent/detect-agent.d.ts +59 -0
- package/dist/agent/detect-agent.d.ts.map +1 -0
- package/dist/agent/detect-agent.js +214 -0
- package/dist/agent/detect-agent.js.map +1 -0
- package/dist/agent/index.d.ts +15 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +14 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/report-agent.d.ts +122 -0
- package/dist/agent/report-agent.d.ts.map +1 -0
- package/dist/agent/report-agent.js +468 -0
- package/dist/agent/report-agent.js.map +1 -0
- package/dist/agent/respond-agent.d.ts +113 -0
- package/dist/agent/respond-agent.d.ts.map +1 -0
- package/dist/agent/respond-agent.js +749 -0
- package/dist/agent/respond-agent.js.map +1 -0
- package/dist/agent-client/index.d.ts +81 -0
- package/dist/agent-client/index.d.ts.map +1 -0
- package/dist/agent-client/index.js +170 -0
- package/dist/agent-client/index.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +295 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +108 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/index.d.ts +66 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +284 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/dashboard/index.d.ts +78 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +455 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/guard-engine.d.ts +108 -0
- package/dist/guard-engine.d.ts.map +1 -0
- package/dist/guard-engine.js +740 -0
- package/dist/guard-engine.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/install/index.d.ts +23 -0
- package/dist/install/index.d.ts.map +1 -0
- package/dist/install/index.js +216 -0
- package/dist/install/index.js.map +1 -0
- package/dist/investigation/index.d.ts +80 -0
- package/dist/investigation/index.d.ts.map +1 -0
- package/dist/investigation/index.js +570 -0
- package/dist/investigation/index.js.map +1 -0
- package/dist/license/index.d.ts +46 -0
- package/dist/license/index.d.ts.map +1 -0
- package/dist/license/index.js +145 -0
- package/dist/license/index.js.map +1 -0
- package/dist/memory/baseline.d.ts +34 -0
- package/dist/memory/baseline.d.ts.map +1 -0
- package/dist/memory/baseline.js +224 -0
- package/dist/memory/baseline.js.map +1 -0
- package/dist/memory/index.d.ts +32 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +58 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/learning.d.ts +35 -0
- package/dist/memory/learning.d.ts.map +1 -0
- package/dist/memory/learning.js +60 -0
- package/dist/memory/learning.js.map +1 -0
- package/dist/monitors/falco-monitor.d.ts +62 -0
- package/dist/monitors/falco-monitor.d.ts.map +1 -0
- package/dist/monitors/falco-monitor.js +226 -0
- package/dist/monitors/falco-monitor.js.map +1 -0
- package/dist/monitors/suricata-monitor.d.ts +80 -0
- package/dist/monitors/suricata-monitor.d.ts.map +1 -0
- package/dist/monitors/suricata-monitor.js +227 -0
- package/dist/monitors/suricata-monitor.js.map +1 -0
- package/dist/notify/email.d.ts +23 -0
- package/dist/notify/email.d.ts.map +1 -0
- package/dist/notify/email.js +124 -0
- package/dist/notify/email.js.map +1 -0
- package/dist/notify/index.d.ts +31 -0
- package/dist/notify/index.d.ts.map +1 -0
- package/dist/notify/index.js +70 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/line-notify.d.ts.map +1 -0
- package/dist/notify/slack.d.ts +21 -0
- package/dist/notify/slack.d.ts.map +1 -0
- package/dist/notify/slack.js +92 -0
- package/dist/notify/slack.js.map +1 -0
- package/dist/notify/telegram.d.ts +21 -0
- package/dist/notify/telegram.d.ts.map +1 -0
- package/dist/notify/telegram.js +89 -0
- package/dist/notify/telegram.js.map +1 -0
- package/dist/response/file-quarantine.d.ts +63 -0
- package/dist/response/file-quarantine.d.ts.map +1 -0
- package/dist/response/file-quarantine.js +137 -0
- package/dist/response/file-quarantine.js.map +1 -0
- package/dist/response/index.d.ts +4 -0
- package/dist/response/index.d.ts.map +1 -0
- package/dist/response/index.js +4 -0
- package/dist/response/index.js.map +1 -0
- package/dist/response/ip-blocker.d.ts +69 -0
- package/dist/response/ip-blocker.d.ts.map +1 -0
- package/dist/response/ip-blocker.js +191 -0
- package/dist/response/ip-blocker.js.map +1 -0
- package/dist/response/process-killer.d.ts +49 -0
- package/dist/response/process-killer.d.ts.map +1 -0
- package/dist/response/process-killer.js +230 -0
- package/dist/response/process-killer.js.map +1 -0
- package/dist/rules/builtin-rules.d.ts +12 -0
- package/dist/rules/builtin-rules.d.ts.map +1 -0
- package/dist/rules/builtin-rules.js +471 -0
- package/dist/rules/builtin-rules.js.map +1 -0
- package/dist/threat-cloud/client-id.d.ts +13 -0
- package/dist/threat-cloud/client-id.d.ts.map +1 -0
- package/dist/threat-cloud/client-id.js +38 -0
- package/dist/threat-cloud/client-id.js.map +1 -0
- package/dist/threat-cloud/index.d.ts +103 -0
- package/dist/threat-cloud/index.d.ts.map +1 -0
- package/dist/threat-cloud/index.js +386 -0
- package/dist/threat-cloud/index.js.map +1 -0
- package/dist/types.d.ts +336 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +42 -0
- package/dist/types.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Dashboard - Real-time monitoring interface
|
|
3
|
+
* Web Dashboard - 即時監控介面
|
|
4
|
+
*
|
|
5
|
+
* Provides an HTTP server with WebSocket push for:
|
|
6
|
+
* - System status overview / 系統狀態概覽
|
|
7
|
+
* - Event timeline / 事件時間軸
|
|
8
|
+
* - Threat map visualization / 威脅地圖視覺化
|
|
9
|
+
* - Configuration management / 配置管理
|
|
10
|
+
* - Language toggle (EN/ZH) / 語言切換
|
|
11
|
+
*
|
|
12
|
+
* Uses only Node.js built-in http module with native WebSocket handshake.
|
|
13
|
+
* 僅使用 Node.js 內建 http 模組搭配原生 WebSocket 交握。
|
|
14
|
+
*
|
|
15
|
+
* @module @panguard-ai/panguard-guard/dashboard
|
|
16
|
+
*/
|
|
17
|
+
import { createServer } from 'node:http';
|
|
18
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
19
|
+
import { createLogger } from '@panguard-ai/core';
|
|
20
|
+
const logger = createLogger('panguard-guard:dashboard');
|
|
21
|
+
/** Maximum requests per minute per IP / 每個 IP 每分鐘最大請求數 */
|
|
22
|
+
const RATE_LIMIT_MAX = 120;
|
|
23
|
+
const RATE_LIMIT_WINDOW_MS = 60_000;
|
|
24
|
+
/** Maximum concurrent WebSocket connections / 最大同時 WebSocket 連線數 */
|
|
25
|
+
const MAX_WS_CLIENTS = 20;
|
|
26
|
+
/**
|
|
27
|
+
* Dashboard Server manages the HTTP + WebSocket real-time dashboard
|
|
28
|
+
* Dashboard 伺服器管理 HTTP + WebSocket 即時儀表板
|
|
29
|
+
*/
|
|
30
|
+
export class DashboardServer {
|
|
31
|
+
server = null;
|
|
32
|
+
wsClients = new Set();
|
|
33
|
+
status;
|
|
34
|
+
recentEvents = [];
|
|
35
|
+
threatMap = [];
|
|
36
|
+
maxRecentEvents = 200;
|
|
37
|
+
port;
|
|
38
|
+
getConfig = null;
|
|
39
|
+
/** API authentication token / API 認證 token */
|
|
40
|
+
authToken;
|
|
41
|
+
/** Rate limiter state / 速率限制狀態 */
|
|
42
|
+
rateLimits = new Map();
|
|
43
|
+
constructor(port) {
|
|
44
|
+
this.port = port;
|
|
45
|
+
this.authToken = randomBytes(32).toString('hex');
|
|
46
|
+
this.status = {
|
|
47
|
+
mode: 'learning',
|
|
48
|
+
uptime: 0,
|
|
49
|
+
eventsProcessed: 0,
|
|
50
|
+
threatsDetected: 0,
|
|
51
|
+
actionsExecuted: 0,
|
|
52
|
+
learningProgress: 0,
|
|
53
|
+
baselineConfidence: 0,
|
|
54
|
+
memoryUsageMB: 0,
|
|
55
|
+
cpuPercent: 0,
|
|
56
|
+
recentVerdicts: [],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Set config getter for the settings API / 設定配置 getter 用於設定 API
|
|
61
|
+
*/
|
|
62
|
+
setConfigGetter(getter) {
|
|
63
|
+
this.getConfig = getter;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Start the dashboard HTTP server / 啟動儀表板 HTTP 伺服器
|
|
67
|
+
*/
|
|
68
|
+
async start() {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
this.server = createServer((req, res) => this.handleRequest(req, res));
|
|
71
|
+
// Handle WebSocket upgrade / 處理 WebSocket 升級
|
|
72
|
+
this.server.on('upgrade', (req, socket, _head) => {
|
|
73
|
+
if (req.url !== '/ws') {
|
|
74
|
+
socket.destroy();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Enforce max WebSocket connections / 限制最大 WebSocket 連線數
|
|
78
|
+
if (this.wsClients.size >= MAX_WS_CLIENTS) {
|
|
79
|
+
logger.warn('Max WebSocket connections reached / WebSocket 連線數已達上限');
|
|
80
|
+
socket.destroy();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Validate origin (localhost only) / 驗證來源(僅 localhost)
|
|
84
|
+
const origin = req.headers.origin ?? '';
|
|
85
|
+
if (origin && !origin.includes('127.0.0.1') && !origin.includes('localhost')) {
|
|
86
|
+
logger.warn(`Rejected WebSocket from origin: ${origin}`);
|
|
87
|
+
socket.destroy();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const key = req.headers['sec-websocket-key'];
|
|
91
|
+
if (!key) {
|
|
92
|
+
socket.destroy();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const acceptKey = createHash('sha1')
|
|
96
|
+
.update(key + '258EAFA5-E914-47DA-95CA-5AB5DC11E65B')
|
|
97
|
+
.digest('base64');
|
|
98
|
+
socket.write('HTTP/1.1 101 Switching Protocols\r\n' +
|
|
99
|
+
'Upgrade: websocket\r\n' +
|
|
100
|
+
'Connection: Upgrade\r\n' +
|
|
101
|
+
`Sec-WebSocket-Accept: ${acceptKey}\r\n` +
|
|
102
|
+
'\r\n');
|
|
103
|
+
const client = { socket, alive: true, connectedAt: Date.now() };
|
|
104
|
+
this.wsClients.add(client);
|
|
105
|
+
// Send initial status / 發送初始狀態
|
|
106
|
+
this.sendToClient(client, {
|
|
107
|
+
type: 'status_update',
|
|
108
|
+
data: this.status,
|
|
109
|
+
timestamp: new Date().toISOString(),
|
|
110
|
+
});
|
|
111
|
+
socket.on('data', (data) => {
|
|
112
|
+
// Handle pong frames / 處理 pong 框架
|
|
113
|
+
if (data.length > 0 && ((data[0] ?? 0) & 0x0f) === 0x0a) {
|
|
114
|
+
client.alive = true;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
socket.on('close', () => {
|
|
118
|
+
this.wsClients.delete(client);
|
|
119
|
+
});
|
|
120
|
+
socket.on('error', () => {
|
|
121
|
+
this.wsClients.delete(client);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
this.server.listen(this.port, '127.0.0.1', () => {
|
|
125
|
+
logger.info(`Dashboard started on http://127.0.0.1:${this.port} / 儀表板已啟動`);
|
|
126
|
+
logger.info(`Dashboard auth token: ${this.authToken}`);
|
|
127
|
+
resolve();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Stop the dashboard server / 停止儀表板伺服器
|
|
133
|
+
*/
|
|
134
|
+
async stop() {
|
|
135
|
+
return new Promise((resolve) => {
|
|
136
|
+
for (const client of this.wsClients) {
|
|
137
|
+
try {
|
|
138
|
+
client.socket.destroy();
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
/* ignore */
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
this.wsClients.clear();
|
|
145
|
+
if (this.server) {
|
|
146
|
+
this.server.close(() => {
|
|
147
|
+
logger.info('Dashboard stopped / 儀表板已停止');
|
|
148
|
+
resolve();
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
resolve();
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Update dashboard status / 更新儀表板狀態
|
|
158
|
+
*/
|
|
159
|
+
updateStatus(update) {
|
|
160
|
+
Object.assign(this.status, update);
|
|
161
|
+
this.broadcast({
|
|
162
|
+
type: 'status_update',
|
|
163
|
+
data: this.status,
|
|
164
|
+
timestamp: new Date().toISOString(),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Push a new event / 推送新事件
|
|
169
|
+
*/
|
|
170
|
+
pushEvent(event) {
|
|
171
|
+
this.recentEvents.push(event);
|
|
172
|
+
if (this.recentEvents.length > this.maxRecentEvents) {
|
|
173
|
+
this.recentEvents.shift();
|
|
174
|
+
}
|
|
175
|
+
this.broadcast(event);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Add a verdict to recent verdicts / 添加判決到最近判決
|
|
179
|
+
*/
|
|
180
|
+
addVerdict(verdict) {
|
|
181
|
+
this.status.recentVerdicts.push(verdict);
|
|
182
|
+
if (this.status.recentVerdicts.length > 50) {
|
|
183
|
+
this.status.recentVerdicts.shift();
|
|
184
|
+
}
|
|
185
|
+
this.broadcast({
|
|
186
|
+
type: 'new_verdict',
|
|
187
|
+
data: verdict,
|
|
188
|
+
timestamp: new Date().toISOString(),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Update threat map / 更新威脅地圖
|
|
193
|
+
*/
|
|
194
|
+
addThreatMapEntry(entry) {
|
|
195
|
+
const existing = this.threatMap.find((t) => t.sourceIP === entry.sourceIP && t.attackType === entry.attackType);
|
|
196
|
+
if (existing) {
|
|
197
|
+
existing.count += entry.count;
|
|
198
|
+
existing.lastSeen = entry.lastSeen;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
this.threatMap.push(entry);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
// HTTP request handling / HTTP 請求處理
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
/**
|
|
208
|
+
* Get the auth token for API access / 取得 API 認證 token
|
|
209
|
+
*/
|
|
210
|
+
getAuthToken() {
|
|
211
|
+
return this.authToken;
|
|
212
|
+
}
|
|
213
|
+
handleRequest(req, res) {
|
|
214
|
+
// Security headers / 安全標頭
|
|
215
|
+
res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:' + this.port);
|
|
216
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
217
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
218
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
219
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
220
|
+
res.setHeader('X-XSS-Protection', '1; mode=block');
|
|
221
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
222
|
+
res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self' ws://127.0.0.1:*");
|
|
223
|
+
if (req.method === 'OPTIONS') {
|
|
224
|
+
res.writeHead(204);
|
|
225
|
+
res.end();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
// Rate limiting / 速率限制
|
|
229
|
+
const clientIP = req.socket.remoteAddress ?? 'unknown';
|
|
230
|
+
if (!this.checkRateLimit(clientIP)) {
|
|
231
|
+
res.writeHead(429, { 'Content-Type': 'application/json' });
|
|
232
|
+
res.end(JSON.stringify({ error: 'Rate limit exceeded' }));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const url = req.url ?? '/';
|
|
236
|
+
// The HTML page is public; API endpoints require auth token
|
|
237
|
+
// HTML 頁面公開;API 端點需要認證 token
|
|
238
|
+
if (url === '/') {
|
|
239
|
+
this.serveIndex(res);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
// Verify auth token for API endpoints / 驗證 API 端點的認證 token
|
|
243
|
+
if (url.startsWith('/api/')) {
|
|
244
|
+
const authHeader = req.headers.authorization ?? '';
|
|
245
|
+
const queryToken = new URL(url, `http://127.0.0.1:${this.port}`).searchParams.get('token');
|
|
246
|
+
const providedToken = authHeader.replace('Bearer ', '') || queryToken;
|
|
247
|
+
if (providedToken !== this.authToken) {
|
|
248
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
249
|
+
res.end(JSON.stringify({ error: 'Unauthorized' }));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const pathname = url.split('?')[0];
|
|
254
|
+
switch (pathname) {
|
|
255
|
+
case '/api/status':
|
|
256
|
+
this.jsonResponse(res, this.status);
|
|
257
|
+
break;
|
|
258
|
+
case '/api/events':
|
|
259
|
+
this.jsonResponse(res, this.recentEvents);
|
|
260
|
+
break;
|
|
261
|
+
case '/api/threat-map':
|
|
262
|
+
this.jsonResponse(res, this.threatMap);
|
|
263
|
+
break;
|
|
264
|
+
case '/api/verdicts':
|
|
265
|
+
this.jsonResponse(res, this.status.recentVerdicts);
|
|
266
|
+
break;
|
|
267
|
+
case '/api/config':
|
|
268
|
+
if (this.getConfig) {
|
|
269
|
+
this.jsonResponse(res, this.getConfig());
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
this.jsonResponse(res, { error: 'Config not available' }, 503);
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
default:
|
|
276
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
277
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/** Check rate limit for IP / 檢查 IP 的速率限制 */
|
|
281
|
+
checkRateLimit(ip) {
|
|
282
|
+
const now = Date.now();
|
|
283
|
+
const entry = this.rateLimits.get(ip);
|
|
284
|
+
if (!entry || now > entry.resetAt) {
|
|
285
|
+
this.rateLimits.set(ip, { count: 1, resetAt: now + RATE_LIMIT_WINDOW_MS });
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
entry.count++;
|
|
289
|
+
return entry.count <= RATE_LIMIT_MAX;
|
|
290
|
+
}
|
|
291
|
+
serveIndex(res) {
|
|
292
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
293
|
+
res.end(DASHBOARD_HTML);
|
|
294
|
+
}
|
|
295
|
+
jsonResponse(res, data, statusCode = 200) {
|
|
296
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
297
|
+
res.end(JSON.stringify(data));
|
|
298
|
+
}
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
// WebSocket helpers / WebSocket 輔助函數
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
sendToClient(client, event) {
|
|
303
|
+
try {
|
|
304
|
+
const data = JSON.stringify(event);
|
|
305
|
+
const payload = Buffer.from(data);
|
|
306
|
+
const frame = this.createWSFrame(payload);
|
|
307
|
+
client.socket.write(frame);
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
this.wsClients.delete(client);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
broadcast(event) {
|
|
314
|
+
for (const client of this.wsClients) {
|
|
315
|
+
this.sendToClient(client, event);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/** Create a WebSocket text frame / 建立 WebSocket 文字框架 */
|
|
319
|
+
createWSFrame(payload) {
|
|
320
|
+
const length = payload.length;
|
|
321
|
+
let header;
|
|
322
|
+
if (length < 126) {
|
|
323
|
+
header = Buffer.alloc(2);
|
|
324
|
+
header[0] = 0x81; // FIN + text opcode
|
|
325
|
+
header[1] = length;
|
|
326
|
+
}
|
|
327
|
+
else if (length < 65536) {
|
|
328
|
+
header = Buffer.alloc(4);
|
|
329
|
+
header[0] = 0x81;
|
|
330
|
+
header[1] = 126;
|
|
331
|
+
header.writeUInt16BE(length, 2);
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
header = Buffer.alloc(10);
|
|
335
|
+
header[0] = 0x81;
|
|
336
|
+
header[1] = 127;
|
|
337
|
+
header.writeBigUInt64BE(BigInt(length), 2);
|
|
338
|
+
}
|
|
339
|
+
return Buffer.concat([header, payload]);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// ---------------------------------------------------------------------------
|
|
343
|
+
// Dashboard HTML template / 儀表板 HTML 範本
|
|
344
|
+
// ---------------------------------------------------------------------------
|
|
345
|
+
const DASHBOARD_HTML = `<!DOCTYPE html>
|
|
346
|
+
<html lang="en">
|
|
347
|
+
<head>
|
|
348
|
+
<meta charset="UTF-8">
|
|
349
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
350
|
+
<title>PanguardGuard Dashboard</title>
|
|
351
|
+
<style>
|
|
352
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
353
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #0f1419; color: #e1e8ed; }
|
|
354
|
+
.header { background: #1a1f2e; padding: 16px 24px; display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #2563eb; }
|
|
355
|
+
.header h1 { font-size: 20px; color: #2563eb; }
|
|
356
|
+
.lang-toggle { background: #2563eb; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 13px; }
|
|
357
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; padding: 16px 24px; }
|
|
358
|
+
.card { background: #1a1f2e; border-radius: 8px; padding: 16px; border: 1px solid #2d3748; }
|
|
359
|
+
.card h3 { font-size: 12px; text-transform: uppercase; color: #718096; margin-bottom: 8px; }
|
|
360
|
+
.card .value { font-size: 28px; font-weight: bold; }
|
|
361
|
+
.status-learning { color: #f6ad55; }
|
|
362
|
+
.status-protection { color: #48bb78; }
|
|
363
|
+
.section { padding: 0 24px 16px; }
|
|
364
|
+
.section h2 { font-size: 16px; margin-bottom: 12px; color: #a0aec0; }
|
|
365
|
+
.event-list { background: #1a1f2e; border-radius: 8px; border: 1px solid #2d3748; max-height: 400px; overflow-y: auto; }
|
|
366
|
+
.event-item { padding: 10px 16px; border-bottom: 1px solid #2d3748; font-size: 13px; font-family: monospace; }
|
|
367
|
+
.event-item:last-child { border-bottom: none; }
|
|
368
|
+
.malicious { border-left: 3px solid #e53e3e; }
|
|
369
|
+
.suspicious { border-left: 3px solid #f6ad55; }
|
|
370
|
+
.benign { border-left: 3px solid #48bb78; }
|
|
371
|
+
.connected { color: #48bb78; }
|
|
372
|
+
.disconnected { color: #e53e3e; }
|
|
373
|
+
.footer { text-align: center; padding: 16px; color: #4a5568; font-size: 12px; }
|
|
374
|
+
</style>
|
|
375
|
+
</head>
|
|
376
|
+
<body>
|
|
377
|
+
<div class="header">
|
|
378
|
+
<h1>PanguardGuard Dashboard</h1>
|
|
379
|
+
<div>
|
|
380
|
+
<span id="ws-status" class="disconnected">Disconnected</span>
|
|
381
|
+
<button class="lang-toggle" onclick="toggleLang()">EN/ZH</button>
|
|
382
|
+
</div>
|
|
383
|
+
</div>
|
|
384
|
+
|
|
385
|
+
<div class="grid" id="status-grid">
|
|
386
|
+
<div class="card"><h3 data-i18n="mode">Mode</h3><div class="value" id="mode">--</div></div>
|
|
387
|
+
<div class="card"><h3 data-i18n="events">Events Processed</h3><div class="value" id="events">0</div></div>
|
|
388
|
+
<div class="card"><h3 data-i18n="threats">Threats Detected</h3><div class="value" id="threats">0</div></div>
|
|
389
|
+
<div class="card"><h3 data-i18n="actions">Actions Executed</h3><div class="value" id="actions">0</div></div>
|
|
390
|
+
<div class="card"><h3 data-i18n="learning">Learning Progress</h3><div class="value" id="learning">0%</div></div>
|
|
391
|
+
<div class="card"><h3 data-i18n="confidence">Baseline Confidence</h3><div class="value" id="confidence">0%</div></div>
|
|
392
|
+
<div class="card"><h3 data-i18n="memory">Memory Usage</h3><div class="value" id="memory">0 MB</div></div>
|
|
393
|
+
<div class="card"><h3 data-i18n="uptime">Uptime</h3><div class="value" id="uptime">0s</div></div>
|
|
394
|
+
</div>
|
|
395
|
+
|
|
396
|
+
<div class="section">
|
|
397
|
+
<h2 data-i18n="timeline">Event Timeline</h2>
|
|
398
|
+
<div class="event-list" id="event-list"></div>
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
<div class="footer">PanguardGuard Security - Panguard Platform</div>
|
|
402
|
+
|
|
403
|
+
<script>
|
|
404
|
+
var i18n = {
|
|
405
|
+
en: { mode: 'Mode', events: 'Events Processed', threats: 'Threats Detected', actions: 'Actions Executed', learning: 'Learning Progress', confidence: 'Baseline Confidence', memory: 'Memory Usage', uptime: 'Uptime', timeline: 'Event Timeline' },
|
|
406
|
+
zh: { mode: '\\u6a21\\u5f0f', events: '\\u5df2\\u8655\\u7406\\u4e8b\\u4ef6', threats: '\\u5df2\\u5075\\u6e2c\\u5a01\\u8105', actions: '\\u5df2\\u57f7\\u884c\\u52d5\\u4f5c', learning: '\\u5b78\\u7fd2\\u9032\\u5ea6', confidence: '\\u57fa\\u7dda\\u4fe1\\u5fc3\\u5ea6', memory: '\\u8a18\\u61b6\\u9ad4\\u4f7f\\u7528', uptime: '\\u904b\\u884c\\u6642\\u9593', timeline: '\\u4e8b\\u4ef6\\u6642\\u9593\\u8ef8' }
|
|
407
|
+
};
|
|
408
|
+
var lang = 'en';
|
|
409
|
+
function toggleLang() {
|
|
410
|
+
lang = lang === 'en' ? 'zh' : 'en';
|
|
411
|
+
document.querySelectorAll('[data-i18n]').forEach(function(el) {
|
|
412
|
+
el.textContent = i18n[lang][el.getAttribute('data-i18n')] || el.textContent;
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function connectWS() {
|
|
417
|
+
var ws = new WebSocket('ws://' + location.host + '/ws');
|
|
418
|
+
var statusEl = document.getElementById('ws-status');
|
|
419
|
+
ws.onopen = function() { statusEl.textContent = 'Connected'; statusEl.className = 'connected'; };
|
|
420
|
+
ws.onclose = function() { statusEl.textContent = 'Disconnected'; statusEl.className = 'disconnected'; setTimeout(connectWS, 3000); };
|
|
421
|
+
ws.onmessage = function(e) {
|
|
422
|
+
var msg = JSON.parse(e.data);
|
|
423
|
+
if (msg.type === 'status_update') updateStatus(msg.data);
|
|
424
|
+
if (msg.type === 'new_verdict' || msg.type === 'new_event') addEvent(msg);
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function updateStatus(s) {
|
|
429
|
+
document.getElementById('mode').textContent = s.mode;
|
|
430
|
+
document.getElementById('mode').className = 'value status-' + s.mode;
|
|
431
|
+
document.getElementById('events').textContent = s.eventsProcessed;
|
|
432
|
+
document.getElementById('threats').textContent = s.threatsDetected;
|
|
433
|
+
document.getElementById('actions').textContent = s.actionsExecuted;
|
|
434
|
+
document.getElementById('learning').textContent = s.learningProgress + '%';
|
|
435
|
+
document.getElementById('confidence').textContent = (s.baselineConfidence * 100).toFixed(1) + '%';
|
|
436
|
+
document.getElementById('memory').textContent = s.memoryUsageMB.toFixed(1) + ' MB';
|
|
437
|
+
document.getElementById('uptime').textContent = Math.floor(s.uptime / 1000) + 's';
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function addEvent(msg) {
|
|
441
|
+
var list = document.getElementById('event-list');
|
|
442
|
+
var div = document.createElement('div');
|
|
443
|
+
var cls = (msg.data && msg.data.conclusion) || 'benign';
|
|
444
|
+
div.className = 'event-item ' + cls;
|
|
445
|
+
div.textContent = msg.timestamp + ' | ' + msg.type + ' | ' + JSON.stringify(msg.data).slice(0, 200);
|
|
446
|
+
list.prepend(div);
|
|
447
|
+
while (list.children.length > 100) list.removeChild(list.lastChild);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
connectWS();
|
|
451
|
+
fetch('/api/status').then(function(r) { return r.json(); }).then(updateStatus).catch(function() {});
|
|
452
|
+
</script>
|
|
453
|
+
</body>
|
|
454
|
+
</html>`;
|
|
455
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardEngine - Main orchestrator for PanguardGuard
|
|
3
|
+
* GuardEngine - PanguardGuard 主引擎
|
|
4
|
+
*
|
|
5
|
+
* Orchestrates the complete detection-analysis-response pipeline:
|
|
6
|
+
* 1. Receives security events from MonitorEngine
|
|
7
|
+
* 2. Routes through DetectAgent -> AnalyzeAgent -> RespondAgent -> ReportAgent
|
|
8
|
+
* 3. Manages Context Memory baseline learning and protection transitions
|
|
9
|
+
* 4. Coordinates notifications, threat cloud, and dashboard updates
|
|
10
|
+
*
|
|
11
|
+
* 協調完整的偵測-分析-回應管線:
|
|
12
|
+
* 1. 從 MonitorEngine 接收安全事件
|
|
13
|
+
* 2. 經過 DetectAgent -> AnalyzeAgent -> RespondAgent -> ReportAgent 路由
|
|
14
|
+
* 3. 管理 Context Memory 基線學習和防護轉換
|
|
15
|
+
* 4. 協調通知、威脅雲和儀表板更新
|
|
16
|
+
*
|
|
17
|
+
* @module @panguard-ai/panguard-guard/guard-engine
|
|
18
|
+
*/
|
|
19
|
+
import type { SecurityEvent } from '@panguard-ai/core';
|
|
20
|
+
import type { GuardConfig, GuardStatus, EnvironmentBaseline, AnalyzeLLM } from './types.js';
|
|
21
|
+
/**
|
|
22
|
+
* GuardEngine is the central orchestrator for all PanguardGuard functionality
|
|
23
|
+
* GuardEngine 是所有 PanguardGuard 功能的中央協調器
|
|
24
|
+
*/
|
|
25
|
+
export declare class GuardEngine {
|
|
26
|
+
private readonly config;
|
|
27
|
+
private mode;
|
|
28
|
+
private baseline;
|
|
29
|
+
private readonly baselinePath;
|
|
30
|
+
private readonly ruleEngine;
|
|
31
|
+
private readonly detectAgent;
|
|
32
|
+
private readonly analyzeAgent;
|
|
33
|
+
private readonly respondAgent;
|
|
34
|
+
private readonly reportAgent;
|
|
35
|
+
private readonly investigationEngine;
|
|
36
|
+
private readonly threatCloud;
|
|
37
|
+
private readonly feedManager;
|
|
38
|
+
private dashboard;
|
|
39
|
+
private readonly pidFile;
|
|
40
|
+
private watchdog;
|
|
41
|
+
private monitorEngine;
|
|
42
|
+
private syslogAdapter;
|
|
43
|
+
private falcoMonitor;
|
|
44
|
+
private suricataMonitor;
|
|
45
|
+
private agentClient;
|
|
46
|
+
private readonly yaraScanner;
|
|
47
|
+
private running;
|
|
48
|
+
private startTime;
|
|
49
|
+
private eventsProcessed;
|
|
50
|
+
private threatsDetected;
|
|
51
|
+
private actionsExecuted;
|
|
52
|
+
private threatCloudUploaded;
|
|
53
|
+
private statusTimer;
|
|
54
|
+
private learningCheckTimer;
|
|
55
|
+
private cloudSyncTimer;
|
|
56
|
+
private eventCallback?;
|
|
57
|
+
constructor(config: GuardConfig, llm?: AnalyzeLLM | null);
|
|
58
|
+
/**
|
|
59
|
+
* Create a GuardEngine with auto-detected LLM provider.
|
|
60
|
+
* Checks env vars for ANTHROPIC_API_KEY, OPENAI_API_KEY, or tries Ollama.
|
|
61
|
+
*/
|
|
62
|
+
static create(config: GuardConfig): Promise<GuardEngine>;
|
|
63
|
+
/**
|
|
64
|
+
* Start the guard engine / 啟動守護引擎
|
|
65
|
+
*/
|
|
66
|
+
start(): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Stop the guard engine / 停止守護引擎
|
|
69
|
+
*/
|
|
70
|
+
stop(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Process a single security event through the full pipeline
|
|
73
|
+
* 透過完整管線處理單一安全事件
|
|
74
|
+
*/
|
|
75
|
+
processEvent(event: SecurityEvent): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Check if learning period should transition to protection
|
|
78
|
+
* 檢查學習期是否應轉換為防護模式
|
|
79
|
+
*/
|
|
80
|
+
private checkLearningTransition;
|
|
81
|
+
/**
|
|
82
|
+
* Periodic Threat Cloud sync: re-fetch rules and blocklist
|
|
83
|
+
* 定期同步 Threat Cloud:重新取得規則和封鎖清單
|
|
84
|
+
*/
|
|
85
|
+
private syncThreatCloud;
|
|
86
|
+
/**
|
|
87
|
+
* Update dashboard with current status / 更新儀表板狀態
|
|
88
|
+
*/
|
|
89
|
+
private updateDashboardStatus;
|
|
90
|
+
/**
|
|
91
|
+
* Register event callback for external consumers (e.g. CLI quiet mode).
|
|
92
|
+
* 註冊事件回調給外部消費者(如 CLI 安靜模式)。
|
|
93
|
+
*/
|
|
94
|
+
setEventCallback(cb: (type: string, data: Record<string, unknown>) => void): void;
|
|
95
|
+
/**
|
|
96
|
+
* Get current engine status / 取得引擎狀態
|
|
97
|
+
*/
|
|
98
|
+
getStatus(): GuardStatus;
|
|
99
|
+
/**
|
|
100
|
+
* Get the current baseline / 取得當前基線
|
|
101
|
+
*/
|
|
102
|
+
getBaseline(): EnvironmentBaseline;
|
|
103
|
+
/**
|
|
104
|
+
* Check if engine is running / 檢查引擎是否執行中
|
|
105
|
+
*/
|
|
106
|
+
isRunning(): boolean;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=guard-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard-engine.d.ts","sourceRoot":"","sources":["../src/guard-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAGX,mBAAmB,EAGnB,UAAU,EAGX,MAAM,YAAY,CAAC;AA8JpB;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,IAAI,CAAY;IACxB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAGtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAG1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyB;IACrD,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAoC;IAGvD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAG1C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,WAAW,CAA+C;IAClE,OAAO,CAAC,kBAAkB,CAA+C;IACzE,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,aAAa,CAAC,CAAwD;gBAElE,MAAM,EAAE,WAAW,EAAE,GAAG,GAAE,UAAU,GAAG,IAAW;IAiF9D;;;OAGG;WACU,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAK9D;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqN5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqD3B;;;OAGG;IACG,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAqKvD;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;;OAGG;YACW,eAAe;IA+B7B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiB7B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,IAAI;IAIjF;;OAEG;IACH,SAAS,IAAI,WAAW;IAkBxB;;OAEG;IACH,WAAW,IAAI,mBAAmB;IAIlC;;OAEG;IACH,SAAS,IAAI,OAAO;CAGrB"}
|