@serve.zone/dcrouter 11.0.0 → 11.0.1
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_serve/bundle.js +560 -560
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.js +24 -16
- package/dist_ts_web/elements/ops-dashboard.js +22 -7
- package/package.json +4 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +24 -16
- package/ts_web/elements/ops-dashboard.ts +21 -6
- package/dist_ts/cache/classes.cache.cleaner.d.ts +0 -47
- package/dist_ts/cache/classes.cache.cleaner.js +0 -130
- package/dist_ts/cache/classes.cached.document.d.ts +0 -76
- package/dist_ts/cache/classes.cached.document.js +0 -100
- package/dist_ts/cache/classes.cachedb.d.ts +0 -60
- package/dist_ts/cache/classes.cachedb.js +0 -126
- package/dist_ts/cache/documents/classes.cached.email.d.ts +0 -125
- package/dist_ts/cache/documents/classes.cached.email.js +0 -337
- package/dist_ts/cache/documents/classes.cached.ip.reputation.d.ts +0 -119
- package/dist_ts/cache/documents/classes.cached.ip.reputation.js +0 -323
- package/dist_ts/cache/documents/index.d.ts +0 -2
- package/dist_ts/cache/documents/index.js +0 -3
- package/dist_ts/cache/index.d.ts +0 -4
- package/dist_ts/cache/index.js +0 -7
- package/dist_ts/monitoring/classes.metricscache.d.ts +0 -32
- package/dist_ts/monitoring/classes.metricscache.js +0 -63
- package/dist_ts/monitoring/classes.metricsmanager.d.ts +0 -178
- package/dist_ts/monitoring/classes.metricsmanager.js +0 -642
- package/dist_ts/monitoring/index.d.ts +0 -1
- package/dist_ts/monitoring/index.js +0 -2
- package/dist_ts/opsserver/handlers/admin.handler.d.ts +0 -31
- package/dist_ts/opsserver/handlers/admin.handler.js +0 -180
- package/dist_ts/opsserver/handlers/config.handler.d.ts +0 -7
- package/dist_ts/opsserver/handlers/config.handler.js +0 -192
- package/dist_ts/opsserver/handlers/logs.handler.d.ts +0 -25
- package/dist_ts/opsserver/handlers/logs.handler.js +0 -256
- package/dist_ts/opsserver/handlers/security.handler.d.ts +0 -9
- package/dist_ts/opsserver/handlers/security.handler.js +0 -231
- package/dist_ts/security/classes.securitylogger.d.ts +0 -144
- package/dist_ts/security/classes.securitylogger.js +0 -233
- package/dist_ts/storage/classes.storagemanager.d.ts +0 -83
- package/dist_ts/storage/classes.storagemanager.js +0 -350
- package/dist_ts/storage/index.d.ts +0 -1
- package/dist_ts/storage/index.js +0 -3
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
3
|
-
import { logBuffer, baseLogger } from '../../logger.js';
|
|
4
|
-
// Module-level singleton: the log push destination is added once and reuses
|
|
5
|
-
// the current OpsServer reference so it survives OpsServer restarts without
|
|
6
|
-
// accumulating duplicate destinations.
|
|
7
|
-
let logPushDestinationInstalled = false;
|
|
8
|
-
let currentOpsServerRef = null;
|
|
9
|
-
export class LogsHandler {
|
|
10
|
-
opsServerRef;
|
|
11
|
-
activeStreamStops = new Set();
|
|
12
|
-
constructor(opsServerRef) {
|
|
13
|
-
this.opsServerRef = opsServerRef;
|
|
14
|
-
this.registerHandlers();
|
|
15
|
-
this.setupLogPushDestination();
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Clean up all active log streams and deactivate the push destination.
|
|
19
|
-
* Called when OpsServer stops.
|
|
20
|
-
*/
|
|
21
|
-
cleanup() {
|
|
22
|
-
// Stop all active follow-mode log streams
|
|
23
|
-
for (const stop of this.activeStreamStops) {
|
|
24
|
-
stop();
|
|
25
|
-
}
|
|
26
|
-
this.activeStreamStops.clear();
|
|
27
|
-
// Deactivate the push destination (it stays registered but becomes a no-op)
|
|
28
|
-
currentOpsServerRef = null;
|
|
29
|
-
}
|
|
30
|
-
registerHandlers() {
|
|
31
|
-
// All log endpoints register directly on viewRouter (valid identity required via middleware)
|
|
32
|
-
const router = this.opsServerRef.viewRouter;
|
|
33
|
-
// Get Recent Logs Handler
|
|
34
|
-
router.addTypedHandler(new plugins.typedrequest.TypedHandler('getRecentLogs', async (dataArg, toolsArg) => {
|
|
35
|
-
const logs = await this.getRecentLogs(dataArg.level, dataArg.category, dataArg.limit || 100, dataArg.offset || 0, dataArg.search, dataArg.timeRange);
|
|
36
|
-
return {
|
|
37
|
-
logs,
|
|
38
|
-
total: logs.length,
|
|
39
|
-
hasMore: false,
|
|
40
|
-
};
|
|
41
|
-
}));
|
|
42
|
-
// Get Log Stream Handler
|
|
43
|
-
router.addTypedHandler(new plugins.typedrequest.TypedHandler('getLogStream', async (dataArg, toolsArg) => {
|
|
44
|
-
// Create a virtual stream for log streaming
|
|
45
|
-
const virtualStream = new plugins.typedrequest.VirtualStream();
|
|
46
|
-
// Set up log streaming
|
|
47
|
-
const streamLogs = this.setupLogStream(virtualStream, dataArg.filters?.level, dataArg.filters?.category, dataArg.follow);
|
|
48
|
-
// Start streaming
|
|
49
|
-
streamLogs.start();
|
|
50
|
-
// Track the stop function so we can clean up on shutdown
|
|
51
|
-
this.activeStreamStops.add(streamLogs.stop);
|
|
52
|
-
return {
|
|
53
|
-
logStream: virtualStream,
|
|
54
|
-
};
|
|
55
|
-
}));
|
|
56
|
-
}
|
|
57
|
-
static mapLogLevel(smartlogLevel) {
|
|
58
|
-
switch (smartlogLevel) {
|
|
59
|
-
case 'silly':
|
|
60
|
-
case 'debug':
|
|
61
|
-
return 'debug';
|
|
62
|
-
case 'warn':
|
|
63
|
-
return 'warn';
|
|
64
|
-
case 'error':
|
|
65
|
-
return 'error';
|
|
66
|
-
default:
|
|
67
|
-
return 'info';
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
static deriveCategory(zone, message) {
|
|
71
|
-
const msg = (message || '').toLowerCase();
|
|
72
|
-
if (msg.includes('[security:') || msg.includes('security'))
|
|
73
|
-
return 'security';
|
|
74
|
-
if (zone === 'email' || msg.includes('email') || msg.includes('smtp') || msg.includes('mta'))
|
|
75
|
-
return 'email';
|
|
76
|
-
if (zone === 'dns' || msg.includes('dns'))
|
|
77
|
-
return 'dns';
|
|
78
|
-
if (msg.includes('smtp'))
|
|
79
|
-
return 'smtp';
|
|
80
|
-
return 'system';
|
|
81
|
-
}
|
|
82
|
-
async getRecentLogs(level, category, limit = 100, offset = 0, search, timeRange) {
|
|
83
|
-
// Compute a timestamp cutoff from timeRange
|
|
84
|
-
let since;
|
|
85
|
-
if (timeRange) {
|
|
86
|
-
const rangeMs = {
|
|
87
|
-
'1h': 3600000,
|
|
88
|
-
'6h': 21600000,
|
|
89
|
-
'24h': 86400000,
|
|
90
|
-
'7d': 604800000,
|
|
91
|
-
'30d': 2592000000,
|
|
92
|
-
};
|
|
93
|
-
since = Date.now() - (rangeMs[timeRange] || 86400000);
|
|
94
|
-
}
|
|
95
|
-
// Map the UI level to smartlog levels for filtering
|
|
96
|
-
const smartlogLevels = level
|
|
97
|
-
? level === 'debug'
|
|
98
|
-
? ['debug', 'silly']
|
|
99
|
-
: level === 'info'
|
|
100
|
-
? ['info', 'ok', 'success', 'note', 'lifecycle']
|
|
101
|
-
: [level]
|
|
102
|
-
: undefined;
|
|
103
|
-
// Fetch a larger batch from buffer, then apply category filter client-side
|
|
104
|
-
const rawEntries = logBuffer.getEntries({
|
|
105
|
-
level: smartlogLevels,
|
|
106
|
-
search,
|
|
107
|
-
since,
|
|
108
|
-
limit: limit * 3, // over-fetch to compensate for category filtering
|
|
109
|
-
offset: 0,
|
|
110
|
-
});
|
|
111
|
-
// Map ILogPackage → UI log format and apply category filter
|
|
112
|
-
const mapped = [];
|
|
113
|
-
for (const pkg of rawEntries) {
|
|
114
|
-
const uiLevel = LogsHandler.mapLogLevel(pkg.level);
|
|
115
|
-
const uiCategory = LogsHandler.deriveCategory(pkg.context?.zone, pkg.message);
|
|
116
|
-
if (category && uiCategory !== category)
|
|
117
|
-
continue;
|
|
118
|
-
mapped.push({
|
|
119
|
-
timestamp: pkg.timestamp,
|
|
120
|
-
level: uiLevel,
|
|
121
|
-
category: uiCategory,
|
|
122
|
-
message: pkg.message,
|
|
123
|
-
metadata: pkg.data,
|
|
124
|
-
});
|
|
125
|
-
if (mapped.length >= limit)
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
return mapped;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Add a log destination to the base logger that pushes entries
|
|
132
|
-
* to all connected ops_dashboard TypedSocket clients.
|
|
133
|
-
*
|
|
134
|
-
* Uses a module-level singleton so the destination is added only once,
|
|
135
|
-
* even across OpsServer restart cycles. The destination reads
|
|
136
|
-
* `currentOpsServerRef` dynamically so it always uses the active server.
|
|
137
|
-
*/
|
|
138
|
-
setupLogPushDestination() {
|
|
139
|
-
// Update the module-level reference so the existing destination uses the new server
|
|
140
|
-
currentOpsServerRef = this.opsServerRef;
|
|
141
|
-
if (logPushDestinationInstalled) {
|
|
142
|
-
return; // destination already registered — just updated the ref
|
|
143
|
-
}
|
|
144
|
-
logPushDestinationInstalled = true;
|
|
145
|
-
baseLogger.addLogDestination({
|
|
146
|
-
async handleLog(logPackage) {
|
|
147
|
-
const opsServer = currentOpsServerRef;
|
|
148
|
-
if (!opsServer)
|
|
149
|
-
return;
|
|
150
|
-
const typedsocket = opsServer.server?.typedserver?.typedsocket;
|
|
151
|
-
if (!typedsocket)
|
|
152
|
-
return;
|
|
153
|
-
let connections;
|
|
154
|
-
try {
|
|
155
|
-
connections = await typedsocket.findAllTargetConnectionsByTag('role', 'ops_dashboard');
|
|
156
|
-
}
|
|
157
|
-
catch {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
if (connections.length === 0)
|
|
161
|
-
return;
|
|
162
|
-
const entry = {
|
|
163
|
-
timestamp: logPackage.timestamp || Date.now(),
|
|
164
|
-
level: LogsHandler.mapLogLevel(logPackage.level),
|
|
165
|
-
category: LogsHandler.deriveCategory(logPackage.context?.zone, logPackage.message),
|
|
166
|
-
message: logPackage.message,
|
|
167
|
-
metadata: logPackage.data,
|
|
168
|
-
};
|
|
169
|
-
for (const conn of connections) {
|
|
170
|
-
try {
|
|
171
|
-
const push = typedsocket.createTypedRequest('pushLogEntry', conn);
|
|
172
|
-
push.fire({ entry }).catch(() => { }); // fire-and-forget
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
// connection may have closed
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
setupLogStream(virtualStream, levelFilter, categoryFilter, follow = true) {
|
|
182
|
-
let intervalId = null;
|
|
183
|
-
let stopped = false;
|
|
184
|
-
let logIndex = 0;
|
|
185
|
-
const stop = () => {
|
|
186
|
-
stopped = true;
|
|
187
|
-
if (intervalId) {
|
|
188
|
-
clearInterval(intervalId);
|
|
189
|
-
intervalId = null;
|
|
190
|
-
}
|
|
191
|
-
this.activeStreamStops.delete(stop);
|
|
192
|
-
};
|
|
193
|
-
const start = () => {
|
|
194
|
-
if (!follow) {
|
|
195
|
-
// Send existing logs and close
|
|
196
|
-
this.getRecentLogs(levelFilter?.[0], categoryFilter?.[0], 100, 0).then(logs => {
|
|
197
|
-
logs.forEach(log => {
|
|
198
|
-
const logData = JSON.stringify(log);
|
|
199
|
-
const encoder = new TextEncoder();
|
|
200
|
-
virtualStream.sendData(encoder.encode(logData));
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
// For follow mode, simulate real-time log streaming
|
|
206
|
-
intervalId = setInterval(async () => {
|
|
207
|
-
if (stopped) {
|
|
208
|
-
// Guard: clear interval if stop() was called between ticks
|
|
209
|
-
clearInterval(intervalId);
|
|
210
|
-
intervalId = null;
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
const categories = ['smtp', 'dns', 'security', 'system', 'email'];
|
|
214
|
-
const levels = ['info', 'warn', 'error', 'debug'];
|
|
215
|
-
const mockCategory = categories[Math.floor(Math.random() * categories.length)];
|
|
216
|
-
const mockLevel = levels[Math.floor(Math.random() * levels.length)];
|
|
217
|
-
// Filter by requested criteria
|
|
218
|
-
if (levelFilter && !levelFilter.includes(mockLevel))
|
|
219
|
-
return;
|
|
220
|
-
if (categoryFilter && !categoryFilter.includes(mockCategory))
|
|
221
|
-
return;
|
|
222
|
-
const logEntry = {
|
|
223
|
-
timestamp: Date.now(),
|
|
224
|
-
level: mockLevel,
|
|
225
|
-
category: mockCategory,
|
|
226
|
-
message: `Real-time log ${logIndex++} from ${mockCategory}`,
|
|
227
|
-
metadata: {
|
|
228
|
-
requestId: plugins.uuid.v4(),
|
|
229
|
-
},
|
|
230
|
-
};
|
|
231
|
-
const logData = JSON.stringify(logEntry);
|
|
232
|
-
const encoder = new TextEncoder();
|
|
233
|
-
try {
|
|
234
|
-
// Use a timeout to detect hung streams (sendData can hang if the
|
|
235
|
-
// VirtualStream's keepAlive loop has ended)
|
|
236
|
-
let timeoutHandle;
|
|
237
|
-
await Promise.race([
|
|
238
|
-
virtualStream.sendData(encoder.encode(logData)).then((result) => {
|
|
239
|
-
clearTimeout(timeoutHandle);
|
|
240
|
-
return result;
|
|
241
|
-
}),
|
|
242
|
-
new Promise((_, reject) => {
|
|
243
|
-
timeoutHandle = setTimeout(() => reject(new Error('stream send timeout')), 10_000);
|
|
244
|
-
}),
|
|
245
|
-
]);
|
|
246
|
-
}
|
|
247
|
-
catch {
|
|
248
|
-
// Stream closed, errored, or timed out — clean up
|
|
249
|
-
stop();
|
|
250
|
-
}
|
|
251
|
-
}, 2000);
|
|
252
|
-
};
|
|
253
|
-
return { start, stop };
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9ncy5oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvb3Bzc2VydmVyL2hhbmRsZXJzL2xvZ3MuaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBRTVDLE9BQU8sS0FBSyxVQUFVLE1BQU0saUNBQWlDLENBQUM7QUFDOUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV4RCw0RUFBNEU7QUFDNUUsNEVBQTRFO0FBQzVFLHVDQUF1QztBQUN2QyxJQUFJLDJCQUEyQixHQUFHLEtBQUssQ0FBQztBQUN4QyxJQUFJLG1CQUFtQixHQUFxQixJQUFJLENBQUM7QUFFakQsTUFBTSxPQUFPLFdBQVc7SUFHRjtJQUZaLGlCQUFpQixHQUFvQixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBRXZELFlBQW9CLFlBQXVCO1FBQXZCLGlCQUFZLEdBQVosWUFBWSxDQUFXO1FBQ3pDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7O09BR0c7SUFDSSxPQUFPO1FBQ1osMENBQTBDO1FBQzFDLEtBQUssTUFBTSxJQUFJLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDMUMsSUFBSSxFQUFFLENBQUM7UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQy9CLDRFQUE0RTtRQUM1RSxtQkFBbUIsR0FBRyxJQUFJLENBQUM7SUFDN0IsQ0FBQztJQUVPLGdCQUFnQjtRQUN0Qiw2RkFBNkY7UUFDN0YsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUM7UUFFNUMsMEJBQTBCO1FBQzFCLE1BQU0sQ0FBQyxlQUFlLENBQ3BCLElBQUksT0FBTyxD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
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { OpsServer } from '../classes.opsserver.js';
|
|
2
|
-
export declare class SecurityHandler {
|
|
3
|
-
private opsServerRef;
|
|
4
|
-
constructor(opsServerRef: OpsServer);
|
|
5
|
-
private registerHandlers;
|
|
6
|
-
private collectSecurityMetrics;
|
|
7
|
-
private getActiveConnections;
|
|
8
|
-
private getRateLimitStatus;
|
|
9
|
-
}
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
3
|
-
import { MetricsManager } from '../../monitoring/index.js';
|
|
4
|
-
export class SecurityHandler {
|
|
5
|
-
opsServerRef;
|
|
6
|
-
constructor(opsServerRef) {
|
|
7
|
-
this.opsServerRef = opsServerRef;
|
|
8
|
-
this.registerHandlers();
|
|
9
|
-
}
|
|
10
|
-
registerHandlers() {
|
|
11
|
-
// All security endpoints register directly on viewRouter (valid identity required via middleware)
|
|
12
|
-
const router = this.opsServerRef.viewRouter;
|
|
13
|
-
// Security Metrics Handler
|
|
14
|
-
router.addTypedHandler(new plugins.typedrequest.TypedHandler('getSecurityMetrics', async (dataArg, toolsArg) => {
|
|
15
|
-
const metrics = await this.collectSecurityMetrics();
|
|
16
|
-
return {
|
|
17
|
-
metrics: {
|
|
18
|
-
blockedIPs: metrics.blockedIPs,
|
|
19
|
-
reputationScores: metrics.reputationScores,
|
|
20
|
-
spamDetected: metrics.spamDetection.detected,
|
|
21
|
-
malwareDetected: metrics.malwareDetected,
|
|
22
|
-
phishingDetected: metrics.phishingDetected,
|
|
23
|
-
authenticationFailures: metrics.authFailures,
|
|
24
|
-
suspiciousActivities: metrics.suspiciousActivities,
|
|
25
|
-
},
|
|
26
|
-
trends: dataArg.includeDetails ? {
|
|
27
|
-
spam: metrics.trends.spam,
|
|
28
|
-
malware: metrics.trends.malware,
|
|
29
|
-
phishing: metrics.trends.phishing,
|
|
30
|
-
} : undefined,
|
|
31
|
-
};
|
|
32
|
-
}));
|
|
33
|
-
// Active Connections Handler
|
|
34
|
-
router.addTypedHandler(new plugins.typedrequest.TypedHandler('getActiveConnections', async (dataArg, toolsArg) => {
|
|
35
|
-
const connections = await this.getActiveConnections(dataArg.protocol, dataArg.state);
|
|
36
|
-
const connectionInfos = connections.map(conn => ({
|
|
37
|
-
id: conn.id,
|
|
38
|
-
remoteAddress: conn.source.ip,
|
|
39
|
-
localAddress: conn.destination.ip,
|
|
40
|
-
startTime: conn.startTime,
|
|
41
|
-
protocol: conn.type === 'http' ? 'https' : conn.type,
|
|
42
|
-
state: conn.status,
|
|
43
|
-
bytesReceived: Math.floor(conn.bytesTransferred / 2),
|
|
44
|
-
bytesSent: Math.floor(conn.bytesTransferred / 2),
|
|
45
|
-
}));
|
|
46
|
-
const summary = {
|
|
47
|
-
total: connectionInfos.length,
|
|
48
|
-
byProtocol: connectionInfos.reduce((acc, conn) => {
|
|
49
|
-
acc[conn.protocol] = (acc[conn.protocol] || 0) + 1;
|
|
50
|
-
return acc;
|
|
51
|
-
}, {}),
|
|
52
|
-
byState: connectionInfos.reduce((acc, conn) => {
|
|
53
|
-
acc[conn.state] = (acc[conn.state] || 0) + 1;
|
|
54
|
-
return acc;
|
|
55
|
-
}, {}),
|
|
56
|
-
};
|
|
57
|
-
return {
|
|
58
|
-
connections: connectionInfos,
|
|
59
|
-
summary,
|
|
60
|
-
};
|
|
61
|
-
}));
|
|
62
|
-
// Network Stats Handler - provides comprehensive network metrics
|
|
63
|
-
router.addTypedHandler(new plugins.typedrequest.TypedHandler('getNetworkStats', async (dataArg, toolsArg) => {
|
|
64
|
-
// Get network stats from MetricsManager if available
|
|
65
|
-
if (this.opsServerRef.dcRouterRef.metricsManager) {
|
|
66
|
-
const networkStats = await this.opsServerRef.dcRouterRef.metricsManager.getNetworkStats();
|
|
67
|
-
// Convert per-IP throughput Map to serializable array
|
|
68
|
-
const throughputByIP = [];
|
|
69
|
-
if (networkStats.throughputByIP) {
|
|
70
|
-
for (const [ip, tp] of networkStats.throughputByIP) {
|
|
71
|
-
throughputByIP.push({ ip, in: tp.in, out: tp.out });
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return {
|
|
75
|
-
connectionsByIP: Array.from(networkStats.connectionsByIP.entries()).map(([ip, count]) => ({ ip, count })),
|
|
76
|
-
throughputRate: networkStats.throughputRate,
|
|
77
|
-
topIPs: networkStats.topIPs,
|
|
78
|
-
totalDataTransferred: networkStats.totalDataTransferred,
|
|
79
|
-
throughputHistory: networkStats.throughputHistory || [],
|
|
80
|
-
throughputByIP,
|
|
81
|
-
requestsPerSecond: networkStats.requestsPerSecond || 0,
|
|
82
|
-
requestsTotal: networkStats.requestsTotal || 0,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
// Fallback if MetricsManager not available
|
|
86
|
-
return {
|
|
87
|
-
connectionsByIP: [],
|
|
88
|
-
throughputRate: { bytesInPerSecond: 0, bytesOutPerSecond: 0 },
|
|
89
|
-
topIPs: [],
|
|
90
|
-
totalDataTransferred: { bytesIn: 0, bytesOut: 0 },
|
|
91
|
-
throughputHistory: [],
|
|
92
|
-
throughputByIP: [],
|
|
93
|
-
requestsPerSecond: 0,
|
|
94
|
-
requestsTotal: 0,
|
|
95
|
-
};
|
|
96
|
-
}));
|
|
97
|
-
// Rate Limit Status Handler
|
|
98
|
-
router.addTypedHandler(new plugins.typedrequest.TypedHandler('getRateLimitStatus', async (dataArg, toolsArg) => {
|
|
99
|
-
const status = await this.getRateLimitStatus(dataArg.domain, dataArg.ip);
|
|
100
|
-
const limits = status.limits.map(limit => ({
|
|
101
|
-
domain: limit.identifier,
|
|
102
|
-
currentRate: limit.current,
|
|
103
|
-
limit: limit.limit,
|
|
104
|
-
remaining: limit.limit - limit.current,
|
|
105
|
-
resetTime: limit.resetAt,
|
|
106
|
-
blocked: limit.status === 'limited',
|
|
107
|
-
}));
|
|
108
|
-
return {
|
|
109
|
-
limits,
|
|
110
|
-
globalLimit: dataArg.includeBlocked ? {
|
|
111
|
-
current: limits.reduce((sum, l) => sum + l.currentRate, 0),
|
|
112
|
-
limit: 1000, // Global limit
|
|
113
|
-
remaining: 1000 - limits.reduce((sum, l) => sum + l.currentRate, 0),
|
|
114
|
-
} : undefined,
|
|
115
|
-
};
|
|
116
|
-
}));
|
|
117
|
-
}
|
|
118
|
-
async collectSecurityMetrics() {
|
|
119
|
-
// Get metrics from MetricsManager if available
|
|
120
|
-
if (this.opsServerRef.dcRouterRef.metricsManager) {
|
|
121
|
-
const securityStats = await this.opsServerRef.dcRouterRef.metricsManager.getSecurityStats();
|
|
122
|
-
return {
|
|
123
|
-
blockedIPs: [], // TODO: Track actual blocked IPs
|
|
124
|
-
reputationScores: {},
|
|
125
|
-
spamDetection: {
|
|
126
|
-
detected: securityStats.spamDetected,
|
|
127
|
-
falsePositives: 0,
|
|
128
|
-
},
|
|
129
|
-
malwareDetected: securityStats.malwareDetected,
|
|
130
|
-
phishingDetected: securityStats.phishingDetected,
|
|
131
|
-
authFailures: securityStats.authFailures,
|
|
132
|
-
suspiciousActivities: 0,
|
|
133
|
-
trends: {
|
|
134
|
-
spam: [],
|
|
135
|
-
malware: [],
|
|
136
|
-
phishing: [],
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
// Fallback if MetricsManager not available
|
|
141
|
-
return {
|
|
142
|
-
blockedIPs: [],
|
|
143
|
-
reputationScores: {},
|
|
144
|
-
spamDetection: {
|
|
145
|
-
detected: 0,
|
|
146
|
-
falsePositives: 0,
|
|
147
|
-
},
|
|
148
|
-
malwareDetected: 0,
|
|
149
|
-
phishingDetected: 0,
|
|
150
|
-
authFailures: 0,
|
|
151
|
-
suspiciousActivities: 0,
|
|
152
|
-
trends: {
|
|
153
|
-
spam: [],
|
|
154
|
-
malware: [],
|
|
155
|
-
phishing: [],
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
async getActiveConnections(protocol, state) {
|
|
160
|
-
const connections = [];
|
|
161
|
-
// Get connection info and network stats from MetricsManager if available
|
|
162
|
-
if (this.opsServerRef.dcRouterRef.metricsManager) {
|
|
163
|
-
const connectionInfo = await this.opsServerRef.dcRouterRef.metricsManager.getConnectionInfo();
|
|
164
|
-
const networkStats = await this.opsServerRef.dcRouterRef.metricsManager.getNetworkStats();
|
|
165
|
-
// Use IP-based connection data from the new metrics API
|
|
166
|
-
if (networkStats.connectionsByIP && networkStats.connectionsByIP.size > 0) {
|
|
167
|
-
let connIndex = 0;
|
|
168
|
-
const publicIp = this.opsServerRef.dcRouterRef.options.publicIp || 'server';
|
|
169
|
-
for (const [ip, count] of networkStats.connectionsByIP) {
|
|
170
|
-
// Create a connection entry for each active IP connection
|
|
171
|
-
for (let i = 0; i < Math.min(count, 5); i++) { // Limit to 5 connections per IP for UI performance
|
|
172
|
-
connections.push({
|
|
173
|
-
id: `conn-${connIndex++}`,
|
|
174
|
-
type: 'http',
|
|
175
|
-
source: {
|
|
176
|
-
ip: ip,
|
|
177
|
-
port: Math.floor(Math.random() * 50000) + 10000, // High port range
|
|
178
|
-
},
|
|
179
|
-
destination: {
|
|
180
|
-
ip: publicIp,
|
|
181
|
-
port: 443,
|
|
182
|
-
service: 'proxy',
|
|
183
|
-
},
|
|
184
|
-
startTime: Date.now() - Math.floor(Math.random() * 3600000), // Within last hour
|
|
185
|
-
bytesTransferred: Math.floor(networkStats.totalDataTransferred.bytesIn / networkStats.connectionsByIP.size),
|
|
186
|
-
status: 'active',
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
else if (connectionInfo.length > 0) {
|
|
192
|
-
// Fallback to route-based connection info if no IP data available
|
|
193
|
-
connectionInfo.forEach((info, index) => {
|
|
194
|
-
connections.push({
|
|
195
|
-
id: `conn-${index}`,
|
|
196
|
-
type: 'http',
|
|
197
|
-
source: {
|
|
198
|
-
ip: 'unknown',
|
|
199
|
-
port: 0,
|
|
200
|
-
},
|
|
201
|
-
destination: {
|
|
202
|
-
ip: this.opsServerRef.dcRouterRef.options.publicIp || 'server',
|
|
203
|
-
port: 443,
|
|
204
|
-
service: info.source,
|
|
205
|
-
},
|
|
206
|
-
startTime: info.lastActivity.getTime(),
|
|
207
|
-
bytesTransferred: 0,
|
|
208
|
-
status: 'active',
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
// Filter by protocol if specified
|
|
214
|
-
if (protocol) {
|
|
215
|
-
return connections.filter(conn => {
|
|
216
|
-
if (protocol === 'https' || protocol === 'http') {
|
|
217
|
-
return conn.type === 'http';
|
|
218
|
-
}
|
|
219
|
-
return conn.type === protocol.replace('s', ''); // smtp/smtps -> smtp
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
return connections;
|
|
223
|
-
}
|
|
224
|
-
async getRateLimitStatus(domain, ip) {
|
|
225
|
-
// TODO: Implement actual rate limit status collection
|
|
226
|
-
return {
|
|
227
|
-
limits: [],
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdXJpdHkuaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL29wc3NlcnZlci9oYW5kbGVycy9zZWN1cml0eS5oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxLQUFLLFVBQVUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM5RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFM0QsTUFBTSxPQUFPLGVBQWU7SUFDTjtJQUFwQixZQUFvQixZQUF1QjtRQUF2QixpQkFBWSxHQUFaLFlBQVksQ0FBVztRQUN6QyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRU8sZ0JBQWdCO1FBQ3RCLGtHQUFrRztRQUNsRyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQztRQUU1QywyQkFBMkI7UUFDM0IsTUFBTSxDQUFDLGVBQWUsQ0FDcEIsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDbkMsb0JBQW9CLEVBQ3BCLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDMUIsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUNwRCxPQUFPO2dCQUNMLE9BQU8sRUFBRTtvQkFDUCxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7b0JBQzlCLGdCQUFnQixFQUFFLE9BQU8sQ0FBQyxnQkFBZ0I7b0JBQzFDLFlBQVksRUFBRSxPQUFPLENBQUMsYUFBYSxDQUFDLFFBQVE7b0JBQzVDLGVBQWUsRUFBRSxPQUFPLENBQUMsZUFBZTtvQkFDeEMsZ0JBQWdCLEVBQUUsT0FBTyxDQUFDLGdCQUFnQjtvQkFDMUMsc0JBQXNCLEVBQUUsT0FBTyxDQUFDLFlBQVk7b0JBQzVDLG9CQUFvQixFQUFFLE9BQU8sQ0FB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
|