@serve.zone/dcrouter 8.1.0 → 9.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.
Files changed (34) hide show
  1. package/dist_serve/bundle.js +1417 -992
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/monitoring/classes.metricsmanager.d.ts +169 -0
  4. package/dist_ts/monitoring/classes.metricsmanager.js +591 -0
  5. package/dist_ts/monitoring/index.d.ts +1 -0
  6. package/dist_ts/monitoring/index.js +2 -0
  7. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +34 -0
  8. package/dist_ts/opsserver/handlers/certificate.handler.js +419 -0
  9. package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +32 -0
  10. package/dist_ts/opsserver/handlers/email-ops.handler.js +226 -0
  11. package/dist_ts/opsserver/handlers/radius.handler.d.ts +8 -0
  12. package/dist_ts/opsserver/handlers/radius.handler.js +296 -0
  13. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +8 -0
  14. package/dist_ts/opsserver/handlers/remoteingress.handler.js +154 -0
  15. package/dist_ts/opsserver/handlers/security.handler.d.ts +11 -0
  16. package/dist_ts/opsserver/handlers/security.handler.js +232 -0
  17. package/dist_ts/opsserver/handlers/stats.handler.d.ts +13 -0
  18. package/dist_ts/opsserver/handlers/stats.handler.js +400 -0
  19. package/dist_ts/security/classes.securitylogger.d.ts +140 -0
  20. package/dist_ts_interfaces/requests/config.d.ts +77 -1
  21. package/dist_ts_web/00_commitinfo_data.js +1 -1
  22. package/dist_ts_web/appstate.d.ts +1 -1
  23. package/dist_ts_web/elements/ops-dashboard.js +15 -5
  24. package/dist_ts_web/elements/ops-view-apitokens.js +8 -4
  25. package/dist_ts_web/elements/ops-view-config.d.ts +10 -8
  26. package/dist_ts_web/elements/ops-view-config.js +215 -297
  27. package/package.json +2 -2
  28. package/ts/00_commitinfo_data.ts +1 -1
  29. package/ts/opsserver/handlers/config.handler.ts +154 -72
  30. package/ts_web/00_commitinfo_data.ts +1 -1
  31. package/ts_web/appstate.ts +1 -1
  32. package/ts_web/elements/ops-dashboard.ts +14 -4
  33. package/ts_web/elements/ops-view-apitokens.ts +7 -3
  34. package/ts_web/elements/ops-view-config.ts +237 -299
@@ -0,0 +1,400 @@
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
+ import { SecurityLogger } from '../../security/classes.securitylogger.js';
5
+ export class StatsHandler {
6
+ opsServerRef;
7
+ typedrouter = new plugins.typedrequest.TypedRouter();
8
+ constructor(opsServerRef) {
9
+ this.opsServerRef = opsServerRef;
10
+ // Add this handler's router to the parent
11
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
12
+ this.registerHandlers();
13
+ }
14
+ registerHandlers() {
15
+ // Server Statistics Handler
16
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getServerStatistics', async (dataArg, toolsArg) => {
17
+ const stats = await this.collectServerStats();
18
+ return {
19
+ stats: {
20
+ uptime: stats.uptime,
21
+ startTime: Date.now() - (stats.uptime * 1000),
22
+ memoryUsage: stats.memoryUsage,
23
+ cpuUsage: stats.cpuUsage,
24
+ activeConnections: stats.activeConnections,
25
+ totalConnections: stats.totalConnections,
26
+ requestsPerSecond: stats.requestsPerSecond,
27
+ throughput: stats.throughput,
28
+ },
29
+ history: dataArg.includeHistory ? stats.history : undefined,
30
+ };
31
+ }));
32
+ // Email Statistics Handler
33
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getEmailStatistics', async (dataArg, toolsArg) => {
34
+ const emailServer = this.opsServerRef.dcRouterRef.emailServer;
35
+ if (!emailServer) {
36
+ return {
37
+ stats: {
38
+ sent: 0,
39
+ received: 0,
40
+ bounced: 0,
41
+ queued: 0,
42
+ failed: 0,
43
+ averageDeliveryTime: 0,
44
+ deliveryRate: 0,
45
+ bounceRate: 0,
46
+ },
47
+ };
48
+ }
49
+ const stats = await this.collectEmailStats();
50
+ return {
51
+ stats: {
52
+ sent: stats.sentToday,
53
+ received: stats.receivedToday,
54
+ bounced: Math.floor(stats.sentToday * stats.bounceRate / 100),
55
+ queued: stats.queueSize,
56
+ failed: 0,
57
+ averageDeliveryTime: 0,
58
+ deliveryRate: stats.deliveryRate,
59
+ bounceRate: stats.bounceRate,
60
+ },
61
+ domainBreakdown: dataArg.includeDetails ? stats.domainBreakdown : undefined,
62
+ };
63
+ }));
64
+ // DNS Statistics Handler
65
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getDnsStatistics', async (dataArg, toolsArg) => {
66
+ const dnsServer = this.opsServerRef.dcRouterRef.dnsServer;
67
+ if (!dnsServer) {
68
+ return {
69
+ stats: {
70
+ totalQueries: 0,
71
+ cacheHits: 0,
72
+ cacheMisses: 0,
73
+ cacheHitRate: 0,
74
+ activeDomains: 0,
75
+ averageResponseTime: 0,
76
+ queryTypes: {},
77
+ },
78
+ };
79
+ }
80
+ const stats = await this.collectDnsStats();
81
+ return {
82
+ stats: {
83
+ totalQueries: stats.totalQueries,
84
+ cacheHits: stats.cacheHits,
85
+ cacheMisses: stats.cacheMisses,
86
+ cacheHitRate: stats.cacheHitRate,
87
+ activeDomains: stats.topDomains.length,
88
+ averageResponseTime: 0,
89
+ queryTypes: stats.queryTypes,
90
+ },
91
+ domainBreakdown: dataArg.includeQueryTypes ? stats.domainBreakdown : undefined,
92
+ };
93
+ }));
94
+ // Queue Status Handler
95
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getQueueStatus', async (dataArg, toolsArg) => {
96
+ const emailServer = this.opsServerRef.dcRouterRef.emailServer;
97
+ const queues = [];
98
+ if (emailServer) {
99
+ const status = await this.getQueueStatus();
100
+ queues.push({
101
+ name: dataArg.queueName || 'default',
102
+ size: status.pending,
103
+ processing: status.active,
104
+ failed: status.failed,
105
+ retrying: status.retrying,
106
+ averageProcessingTime: 0,
107
+ });
108
+ }
109
+ return {
110
+ queues,
111
+ totalItems: queues.reduce((sum, q) => sum + q.size + q.processing + q.failed + q.retrying, 0),
112
+ };
113
+ }));
114
+ // Health Status Handler
115
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getHealthStatus', async (dataArg, toolsArg) => {
116
+ const health = await this.checkHealthStatus();
117
+ return {
118
+ health: {
119
+ healthy: health.healthy,
120
+ uptime: process.uptime(),
121
+ services: health.services.reduce((acc, service) => {
122
+ acc[service.name] = {
123
+ status: service.status,
124
+ message: service.message,
125
+ lastCheck: Date.now(),
126
+ };
127
+ return acc;
128
+ }, {}),
129
+ version: '2.12.0', // TODO: Get from package.json
130
+ },
131
+ };
132
+ }));
133
+ // Combined Metrics Handler - More efficient for frontend polling
134
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getCombinedMetrics', async (dataArg, toolsArg) => {
135
+ const sections = dataArg.sections || {
136
+ server: true,
137
+ email: true,
138
+ dns: true,
139
+ security: true,
140
+ network: true,
141
+ };
142
+ const metrics = {};
143
+ // Run all metrics collection in parallel
144
+ const promises = [];
145
+ if (sections.server) {
146
+ promises.push(this.collectServerStats().then(stats => {
147
+ metrics.server = {
148
+ uptime: stats.uptime,
149
+ startTime: Date.now() - (stats.uptime * 1000),
150
+ memoryUsage: stats.memoryUsage,
151
+ cpuUsage: stats.cpuUsage,
152
+ activeConnections: stats.activeConnections,
153
+ totalConnections: stats.totalConnections,
154
+ requestsPerSecond: stats.requestsPerSecond,
155
+ throughput: stats.throughput,
156
+ };
157
+ }));
158
+ }
159
+ if (sections.email) {
160
+ promises.push(this.collectEmailStats().then(stats => {
161
+ // Get time-series data from MetricsManager
162
+ const timeSeries = this.opsServerRef.dcRouterRef.metricsManager
163
+ ? this.opsServerRef.dcRouterRef.metricsManager.getEmailTimeSeries(24)
164
+ : undefined;
165
+ metrics.email = {
166
+ sent: stats.sentToday,
167
+ received: stats.receivedToday,
168
+ bounced: Math.floor(stats.sentToday * stats.bounceRate / 100),
169
+ queued: stats.queueSize,
170
+ failed: 0,
171
+ averageDeliveryTime: 0,
172
+ deliveryRate: stats.deliveryRate,
173
+ bounceRate: stats.bounceRate,
174
+ timeSeries,
175
+ };
176
+ }));
177
+ }
178
+ if (sections.dns) {
179
+ promises.push(this.collectDnsStats().then(stats => {
180
+ // Get time-series data from MetricsManager
181
+ const timeSeries = this.opsServerRef.dcRouterRef.metricsManager
182
+ ? this.opsServerRef.dcRouterRef.metricsManager.getDnsTimeSeries(24)
183
+ : undefined;
184
+ metrics.dns = {
185
+ totalQueries: stats.totalQueries,
186
+ cacheHits: stats.cacheHits,
187
+ cacheMisses: stats.cacheMisses,
188
+ cacheHitRate: stats.cacheHitRate,
189
+ activeDomains: stats.topDomains.length,
190
+ averageResponseTime: 0,
191
+ queryTypes: stats.queryTypes,
192
+ timeSeries,
193
+ recentQueries: stats.recentQueries,
194
+ };
195
+ }));
196
+ }
197
+ if (sections.security && this.opsServerRef.dcRouterRef.metricsManager) {
198
+ promises.push(this.opsServerRef.dcRouterRef.metricsManager.getSecurityStats().then(stats => {
199
+ // Get recent events from the SecurityLogger singleton
200
+ const securityLogger = SecurityLogger.getInstance();
201
+ const recentEvents = securityLogger.getRecentEvents(50).map((evt) => ({
202
+ timestamp: evt.timestamp,
203
+ level: evt.level,
204
+ type: evt.type,
205
+ message: evt.message,
206
+ details: evt.details,
207
+ ipAddress: evt.ipAddress,
208
+ domain: evt.domain,
209
+ success: evt.success,
210
+ }));
211
+ metrics.security = {
212
+ blockedIPs: stats.blockedIPs,
213
+ reputationScores: {},
214
+ spamDetected: stats.spamDetected,
215
+ malwareDetected: stats.malwareDetected,
216
+ phishingDetected: stats.phishingDetected,
217
+ authenticationFailures: stats.authFailures,
218
+ suspiciousActivities: stats.totalThreatsBlocked,
219
+ recentEvents,
220
+ };
221
+ }));
222
+ }
223
+ if (sections.network && this.opsServerRef.dcRouterRef.metricsManager) {
224
+ promises.push((async () => {
225
+ const stats = await this.opsServerRef.dcRouterRef.metricsManager.getNetworkStats();
226
+ const serverStats = await this.collectServerStats();
227
+ // Build per-IP bandwidth lookup from throughputByIP
228
+ const ipBandwidth = new Map();
229
+ if (stats.throughputByIP) {
230
+ for (const [ip, tp] of stats.throughputByIP) {
231
+ ipBandwidth.set(ip, { in: tp.in, out: tp.out });
232
+ }
233
+ }
234
+ metrics.network = {
235
+ totalBandwidth: {
236
+ in: stats.throughputRate.bytesInPerSecond,
237
+ out: stats.throughputRate.bytesOutPerSecond,
238
+ },
239
+ totalBytes: {
240
+ in: stats.totalDataTransferred.bytesIn,
241
+ out: stats.totalDataTransferred.bytesOut,
242
+ },
243
+ activeConnections: serverStats.activeConnections,
244
+ connectionDetails: [],
245
+ topEndpoints: stats.topIPs.map(ip => ({
246
+ endpoint: ip.ip,
247
+ requests: ip.count,
248
+ bandwidth: ipBandwidth.get(ip.ip) || { in: 0, out: 0 },
249
+ })),
250
+ throughputHistory: stats.throughputHistory || [],
251
+ requestsPerSecond: stats.requestsPerSecond || 0,
252
+ requestsTotal: stats.requestsTotal || 0,
253
+ };
254
+ })());
255
+ }
256
+ await Promise.all(promises);
257
+ return {
258
+ metrics,
259
+ timestamp: Date.now(),
260
+ };
261
+ }));
262
+ }
263
+ async collectServerStats() {
264
+ // Get metrics from MetricsManager if available
265
+ if (this.opsServerRef.dcRouterRef.metricsManager) {
266
+ const serverStats = await this.opsServerRef.dcRouterRef.metricsManager.getServerStats();
267
+ return {
268
+ uptime: serverStats.uptime,
269
+ cpuUsage: serverStats.cpuUsage,
270
+ memoryUsage: serverStats.memoryUsage,
271
+ requestsPerSecond: serverStats.requestsPerSecond,
272
+ activeConnections: serverStats.activeConnections,
273
+ totalConnections: serverStats.totalConnections,
274
+ throughput: serverStats.throughput,
275
+ history: [], // TODO: Implement history tracking
276
+ };
277
+ }
278
+ // Fallback to basic stats if MetricsManager not available
279
+ const uptime = process.uptime();
280
+ const memUsage = process.memoryUsage();
281
+ const cpuUsage = plugins.os.loadavg()[0] * 100 / plugins.os.cpus().length;
282
+ return {
283
+ uptime,
284
+ cpuUsage: {
285
+ user: cpuUsage * 0.7,
286
+ system: cpuUsage * 0.3,
287
+ },
288
+ memoryUsage: {
289
+ heapUsed: memUsage.heapUsed,
290
+ heapTotal: memUsage.heapTotal,
291
+ external: memUsage.external,
292
+ rss: memUsage.rss,
293
+ },
294
+ requestsPerSecond: 0,
295
+ activeConnections: 0,
296
+ totalConnections: 0,
297
+ throughput: { bytesIn: 0, bytesOut: 0, bytesInPerSecond: 0, bytesOutPerSecond: 0 },
298
+ history: [],
299
+ };
300
+ }
301
+ async collectEmailStats() {
302
+ // Get metrics from MetricsManager if available
303
+ if (this.opsServerRef.dcRouterRef.metricsManager) {
304
+ const emailStats = await this.opsServerRef.dcRouterRef.metricsManager.getEmailStats();
305
+ return {
306
+ sentToday: emailStats.sentToday,
307
+ receivedToday: emailStats.receivedToday,
308
+ bounceRate: emailStats.bounceRate,
309
+ deliveryRate: emailStats.deliveryRate,
310
+ queueSize: emailStats.queueSize,
311
+ };
312
+ }
313
+ // Fallback if MetricsManager not available
314
+ return {
315
+ sentToday: 0,
316
+ receivedToday: 0,
317
+ bounceRate: 0,
318
+ deliveryRate: 100,
319
+ queueSize: 0,
320
+ };
321
+ }
322
+ async collectDnsStats() {
323
+ // Get metrics from MetricsManager if available
324
+ if (this.opsServerRef.dcRouterRef.metricsManager) {
325
+ const dnsStats = await this.opsServerRef.dcRouterRef.metricsManager.getDnsStats();
326
+ return {
327
+ queriesPerSecond: dnsStats.queriesPerSecond,
328
+ totalQueries: dnsStats.totalQueries,
329
+ cacheHits: dnsStats.cacheHits,
330
+ cacheMisses: dnsStats.cacheMisses,
331
+ cacheHitRate: dnsStats.cacheHitRate,
332
+ topDomains: dnsStats.topDomains,
333
+ queryTypes: dnsStats.queryTypes,
334
+ recentQueries: dnsStats.recentQueries,
335
+ };
336
+ }
337
+ // Fallback if MetricsManager not available
338
+ return {
339
+ queriesPerSecond: 0,
340
+ totalQueries: 0,
341
+ cacheHits: 0,
342
+ cacheMisses: 0,
343
+ cacheHitRate: 0,
344
+ topDomains: [],
345
+ queryTypes: {},
346
+ };
347
+ }
348
+ async getQueueStatus() {
349
+ // TODO: Implement actual queue status collection
350
+ return {
351
+ pending: 0,
352
+ active: 0,
353
+ failed: 0,
354
+ retrying: 0,
355
+ items: [],
356
+ };
357
+ }
358
+ async checkHealthStatus() {
359
+ const services = [];
360
+ // Check HTTP Proxy
361
+ if (this.opsServerRef.dcRouterRef.smartProxy) {
362
+ services.push({
363
+ name: 'HTTP/HTTPS Proxy',
364
+ status: 'healthy',
365
+ });
366
+ }
367
+ // Check Email Server
368
+ if (this.opsServerRef.dcRouterRef.emailServer) {
369
+ services.push({
370
+ name: 'Email Server',
371
+ status: 'healthy',
372
+ });
373
+ }
374
+ // Check DNS Server
375
+ if (this.opsServerRef.dcRouterRef.dnsServer) {
376
+ services.push({
377
+ name: 'DNS Server',
378
+ status: 'healthy',
379
+ });
380
+ }
381
+ // Check OpsServer
382
+ services.push({
383
+ name: 'OpsServer',
384
+ status: 'healthy',
385
+ });
386
+ const healthy = services.every(s => s.status === 'healthy');
387
+ return {
388
+ healthy,
389
+ services,
390
+ checks: [
391
+ {
392
+ name: 'Memory Usage',
393
+ passed: process.memoryUsage().heapUsed < (plugins.os.totalmem() * 0.9),
394
+ message: 'Memory usage within limits',
395
+ },
396
+ ],
397
+ };
398
+ }
399
+ }
400
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdHMuaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL29wc3NlcnZlci9oYW5kbGVycy9zdGF0cy5oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxLQUFLLFVBQVUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM5RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDBDQUEwQyxDQUFDO0FBRTFFLE1BQU0sT0FBTyxZQUFZO0lBR0g7SUFGYixXQUFXLEdBQUcsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBRTVELFlBQW9CLFlBQXVCO1FBQXZCLGlCQUFZLEdBQVosWUFBWSxDQUFXO1FBQ3pDLDBDQUEwQztRQUMxQyxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQy9ELElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFTyxnQkFBZ0I7UUFDdEIsNEJBQTRCO1FBQzVCLElBQUksQ0FBQyxXQUFXLENBQUMsZUFBZSxDQUM5QixJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUNuQyxxQkFBcUIsRUFDckIsS0FBSyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRTtZQUMxQixNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzlDLE9BQU87Z0JBQ0wsS0FBSyxFQUFFO29CQUNMLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTTtvQkFDcEIsU0FBUyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO29CQUM3QyxXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVc7b0JBQzlCLFFBQVEsRUFBRSxLQUFLLENBQUMsUUFBUTtvQkFDeEIsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtvQkFDMUMsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLGdCQUFnQjtvQkFDeEMsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtvQkFDMUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO2lCQUM3QjtnQkFDRCxPQUFPLEVBQUUsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUzthQUM1RCxDQUFDO1FBQ0osQ0FBQyxDQUNGLENBQ0YsQ0FBQztRQUVGLDJCQUEyQjtRQUMzQixJQUFJLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FDOUIsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDbkMsb0JBQW9CLEVBQ3BCLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDMUIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDO1lBQzlELElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDakIsT0FBTztvQkFDTCxLQUFLLEVBQUU7d0JBQ0wsSUFBSSxFQUFFLENBQUM7d0JBQ1AsUUFBUSxFQUFFLENBQUM7d0JBQ1gsT0FBTyxFQUFFLENBQUM7d0JBQ1YsTUFBTSxFQUFFLENBQUM7d0JBQ1QsTUFBTSxFQUFFLENBQUM7d0JBQ1QsbUJBQW1CLEVBQUUsQ0FBQzt3QkFDdEIsWUFBWSxFQUFFLENBQUM7d0JBQ2YsVUFBVSxFQUFFLENBQUM7cUJBQ2Q7aUJBQ0YsQ0FBQztZQUNKLENBQUM7WUFFRCxNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzdDLE9BQU87Z0JBQ0wsS0FBSyxFQUFFO29CQUNMLElBQUksRUFBRSxLQUFLLENBQUMsU0FBUztvQkFDckIsUUFBUSxFQUFFLEtBQUssQ0FBQyxhQUFhO29CQUM3QixPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxVQUFVLEdBQUcsR0FBRyxDQUFDO29CQUM3RCxNQUFNLEVBQUUsS0FBSyxDQUFDLFNBQVM7b0JBQ3ZCLE1BQU0sRUFBRSxDQUFDO29CQUNULG1CQUFtQixFQUFFLENBQUM7b0JBQ3RCLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTtvQkFDaEMsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO2lCQUM3QjtnQkFDRCxlQUFlLEVBQUUsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsU0FBUzthQUM1RSxDQUFDO1FBQ0osQ0FBQyxDQUNGLENBQ0YsQ0FBQztRQUVGLHlCQUF5QjtRQUN6QixJQUFJLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FDOUIsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDbkMsa0JBQWtCLEVBQ2xCLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDMUIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDO1lBQzFELElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDZixPQUFPO29CQUNMLEtBQUssRUFBRTt3QkFDTCxZQUFZLEVBQUUsQ0FBQzt3QkFDZixTQUFTLEVBQUUsQ0FBQzt3QkFDWixXQUFXLEVBQUUsQ0FBQzt3QkFDZCxZQUFZLEVBQUUsQ0FBQzt3QkFDZixhQUFhLEVBQUUsQ0FBQzt3QkFDaEIsbUJBQW1CLEVBQUUsQ0FBQzt3QkFDdEIsVUFBVSxFQUFFLEVBQUU7cUJBQ2Y7aUJBQ0YsQ0FBQztZQUNKLENBQUM7WUFFRCxNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUMzQyxPQUFPO2dCQUNMLEtBQUssRUFBRTtvQkFDTCxZQUFZLEVBQUUsS0FBSyxDQUFDLFlBQVk7b0JBQ2hDLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUztvQkFDMUIsV0FBVyxFQUFFLEtBQUssQ0FBQyxXQUFXO29CQUM5QixZQUFZLEVBQUUsS0FBSyxDQUFDLFlBQVk7b0JBQ2hDLGFBQWEsRUFBRSxLQUFLLENBQUMsVUFBVSxDQUFDLE1BQU07b0JBQ3RDLG1CQUFtQixFQUFFLENBQUM7b0JBQ3RCLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTtpQkFDN0I7Z0JBQ0QsZUFBZSxFQUFFLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsU0FBUzthQUMvRSxDQUFDO1FBQ0osQ0FBQyxDQUNGLENBQ0YsQ0FBQztRQUVGLHVCQUF1QjtRQUN2QixJQUFJLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FDOUIsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDbkMsZ0JBQWdCLEVBQ2hCLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDMUIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDO1lBQzlELE1BQU0sTUFBTSxHQUFtQyxFQUFFLENBQUM7WUFFbEQsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDaEIsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQzNDLE1BQU0sQ0FBQyxJQUFJLENBQUM7b0JBQ1YsSUFBSSxFQUFFLE9BQU8sQ0FBQyxTQUFTLElBQUksU0FBUztvQkFDcEMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxPQUFPO29CQUNwQixVQUFVLEVBQUUsTUFBTSxDQUFDLE1BQU07b0JBQ3pCLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTTtvQkFDckIsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRO29CQUN6QixxQkFBcUIsRUFBRSxDQUFDO2lCQUN6QixDQUFDLENBQUM7WUFDTCxDQUFDO1lBRUQsT0FBTztnQkFDTCxNQUFNO2dCQUNOLFVBQVUsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO2FBQzlGLENBQUM7UUFDSixDQUFDLENBQ0YsQ0FDRixDQUFDO1FBRUYsd0JBQXdCO1FBQ3hCLElBQUksQ0FBQyxXQUFXLENBQUMsZUFBZSxDQUM5QixJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUNuQyxpQkFBaUIsRUFDakIsS0FBSyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRTtZQUMxQixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzlDLE9BQU87Z0JBQ0wsTUFBTSxFQUFFO29CQUNOLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTztvQkFDdkIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLEVBQUU7b0JBQ3hCLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxPQUFPLEVBQUUsRUFBRTt3QkFDaEQsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRzs0QkFDbEIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNOzRCQUN0QixPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU87NEJBQ3hCLFNBQVMsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO3lCQUN0QixDQUFDO3dCQUNGLE9BQU8sR0FBRyxDQUFDO29CQUNiLENBQUMsRUFBRSxFQUFTLENBQUM7b0JBQ2IsT0FBTyxFQUFFLFFBQVEsRUFBRSw4QkFBOEI7aUJBQ2xEO2FBQ0YsQ0FBQztRQUNKLENBQUMsQ0FDRixDQUNGLENBQUM7UUFFRixpRUFBaUU7UUFDakUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQzlCLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ25DLG9CQUFvQixFQUNwQixLQUFLLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxFQUFFO1lBQzFCLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxRQUFRLElBQUk7Z0JBQ25DLE1BQU0sRUFBRSxJQUFJO2dCQUNaLEtBQUssRUFBRSxJQUFJO2dCQUNYLEdBQUcsRUFBRSxJQUFJO2dCQUNULFFBQVEsRUFBRSxJQUFJO2dCQUNkLE9BQU8sRUFBRSxJQUFJO2FBQ2QsQ0FBQztZQUVGLE1BQU0sT0FBTyxHQUFRLEVBQUUsQ0FBQztZQUV4Qix5Q0FBeUM7WUFDekMsTUFBTSxRQUFRLEdBQW9CLEVBQUUsQ0FBQztZQUVyQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDcEIsUUFBUSxDQUFDLElBQUksQ0FDWCxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUU7b0JBQ3JDLE9BQU8sQ0FBQyxNQUFNLEdBQUc7d0JBQ2YsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO3dCQUNwQixTQUFTLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7d0JBQzdDLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVzt3QkFDOUIsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRO3dCQUN4QixpQkFBaUIsRUFBRSxLQUFLLENBQUMsaUJBQWlCO3dCQUMxQyxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsZ0JBQWdCO3dCQUN4QyxpQkFBaUIsRUFBRSxLQUFLLENBQUMsaUJBQWlCO3dCQUMxQyxVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7cUJBQzdCLENBQUM7Z0JBQ0osQ0FBQyxDQUFDLENBQ0gsQ0FBQztZQUNKLENBQUM7WUFFRCxJQUFJLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDbkIsUUFBUSxDQUFDLElBQUksQ0FDWCxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUU7b0JBQ3BDLDJDQUEyQztvQkFDM0MsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsY0FBYzt3QkFDN0QsQ0FBQyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUM7d0JBQ3JFLENBQUMsQ0FBQyxTQUFTLENBQUM7b0JBRWQsT0FBTyxDQUFDLEtBQUssR0FBRzt3QkFDZCxJQUFJLEVBQUUsS0FBSyxDQUFDLFNBQVM7d0JBQ3JCLFFBQVEsRUFBRSxLQUFLLENBQUMsYUFBYTt3QkFDN0IsT0FBTyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUMsVUFBVSxHQUFHLEdBQUcsQ0FBQzt3QkFDN0QsTUFBTSxFQUFFLEtBQUssQ0FBQyxTQUFTO3dCQUN2QixNQUFNLEVBQUUsQ0FBQzt3QkFDVCxtQkFBbUIsRUFBRSxDQUFDO3dCQUN0QixZQUFZLEVBQUUsS0FBSyxDQUFDLFlBQVk7d0JBQ2hDLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTt3QkFDNUIsVUFBVTtxQkFDWCxDQUFDO2dCQUNKLENBQUMsQ0FBQyxDQUNILENBQUM7WUFDSixDQUFDO1lBRUQsSUFBSSxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ2pCLFFBQVEsQ0FBQyxJQUFJLENBQ1gsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRTtvQkFDbEMsMkNBQTJDO29CQUMzQyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxjQUFjO3dCQUM3RCxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQzt3QkFDbkUsQ0FBQyxDQUFDLFNBQVMsQ0FBQztvQkFFZCxPQUFPLENBQUMsR0FBRyxHQUFHO3dCQUNaLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTt3QkFDaEMsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO3dCQUMxQixXQUFXLEVBQUUsS0FBSyxDQUFDLFdBQVc7d0JBQzlCLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTt3QkFDaEMsYUFBYSxFQUFFLEtBQUssQ0FBQyxVQUFVLENBQUMsTUFBTTt3QkFDdEMsbUJBQW1CLEVBQUUsQ0FBQzt3QkFDdEIsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO3dCQUM1QixVQUFVO3dCQUNWLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYTtxQkFDbkMsQ0FBQztnQkFDSixDQUFDLENBQUMsQ0FDSCxDQUFDO1lBQ0osQ0FBQztZQUVELElBQUksUUFBUSxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdEUsUUFBUSxDQUFDLElBQUksQ0FDWCxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUU7b0JBQzNFLHNEQUFzRDtvQkFDdEQsTUFBTSxjQUFjLEdBQUcsY0FBYyxDQUFDLFdBQVcsRUFBRSxDQUFDO29CQUNwRCxNQUFNLFlBQVksR0FBRyxjQUFjLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQzt3QkFDcEUsU0FBUyxFQUFFLEdBQUcsQ0FBQyxTQUFTO3dCQUN4QixLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7d0JBQ2hCLElBQUksRUFBRSxHQUFHLENBQUMsSUFBSTt3QkFDZCxPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU87d0JBQ3BCLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTzt3QkFDcEIsU0FBUyxFQUFFLEdBQUcsQ0FBQyxTQUFTO3dCQUN4QixNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU07d0JBQ2xCLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztxQkFDckIsQ0FBQyxDQUFDLENBQUM7b0JBRUosT0FBTyxDQUFDLFFBQVEsR0FBRzt3QkFDakIsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO3dCQUM1QixnQkFBZ0IsRUFBRSxFQUFFO3dCQUNwQixZQUFZLEVBQUUsS0FBSyxDQUFDLFlBQVk7d0JBQ2hDLGVBQWUsRUFBRSxLQUFLLENBQUMsZUFBZTt3QkFDdEMsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLGdCQUFnQjt3QkFDeEMsc0JBQXNCLEVBQUUsS0FBSyxDQUFDLFlBQVk7d0JBQzFDLG9CQUFvQixFQUFFLEtBQUssQ0FBQyxtQkFBbUI7d0JBQy9DLFlBQVk7cUJBQ2IsQ0FBQztnQkFDSixDQUFDLENBQUMsQ0FDSCxDQUFDO1lBQ0osQ0FBQztZQUVELElBQUksUUFBUSxDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDckUsUUFBUSxDQUFDLElBQUksQ0FDWCxDQUFDLEtBQUssSUFBSSxFQUFFO29CQUNWLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLGVBQWUsRUFBRSxDQUFDO29CQUNuRixNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO29CQUVwRCxvREFBb0Q7b0JBQ3BELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUF1QyxDQUFDO29CQUNuRSxJQUFJLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQzt3QkFDekIsS0FBSyxNQUFNLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxJQUFJLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQzs0QkFDNUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7d0JBQ2xELENBQUM7b0JBQ0gsQ0FBQztvQkFFRCxPQUFPLENBQUMsT0FBTyxHQUFHO3dCQUNoQixjQUFjLEVBQUU7NEJBQ2QsRUFBRSxFQUFFLEtBQUssQ0FBQyxjQUFjLENBQUMsZ0JBQWdCOzRCQUN6QyxHQUFHLEVBQUUsS0FBSyxDQUFDLGNBQWMsQ0FBQyxpQkFBaUI7eUJBQzVDO3dCQUNELFVBQVUsRUFBRTs0QkFDVixFQUFFLEVBQUUsS0FBSyxDQUFDLG9CQUFvQixDQUFDLE9BQU87NEJBQ3RDLEdBQUcsRUFBRSxLQUFLLENBQUMsb0JBQW9CLENBQUMsUUFBUTt5QkFDekM7d0JBQ0QsaUJBQWlCLEVBQUUsV0FBVyxDQUFDLGlCQUFpQjt3QkFDaEQsaUJBQWlCLEVBQUUsRUFBRTt3QkFDckIsWUFBWSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQzs0QkFDcEMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxFQUFFOzRCQUNmLFFBQVEsRUFBRSxFQUFFLENBQUMsS0FBSzs0QkFDbEIsU0FBUyxFQUFFLFdBQVcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFO3lCQUN2RCxDQUFDLENBQUM7d0JBQ0gsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQixJQUFJLEVBQUU7d0JBQ2hELGlCQUFpQixFQUFFLEtBQUssQ0FBQyxpQkFBaUIsSUFBSSxDQUFDO3dCQUMvQyxhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWEsSUFBSSxDQUFDO3FCQUN4QyxDQUFDO2dCQUNKLENBQUMsQ0FBQyxFQUFFLENBQ0wsQ0FBQztZQUNKLENBQUM7WUFFRCxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7WUFFNUIsT0FBTztnQkFDTCxPQUFPO2dCQUNQLFNBQVMsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO2FBQ3RCLENBQUM7UUFDSixDQUFDLENBQ0YsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVPLEtBQUssQ0FBQyxrQkFBa0I7UUFnQjlCLCtDQUErQztRQUMvQyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ2pELE1BQU0sV0FBVyxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hGLE9BQU87Z0JBQ0wsTUFBTSxFQUFFLFdBQVcsQ0FBQyxNQUFNO2dCQUMxQixRQUFRLEVBQUUsV0FBVyxDQUFDLFFBQVE7Z0JBQzlCLFdBQVcsRUFBRSxXQUFXLENBQUMsV0FBVztnQkFDcEMsaUJBQWlCLEVBQUUsV0FBVyxDQUFDLGlCQUFpQjtnQkFDaEQsaUJBQWlCLEVBQUUsV0FBVyxDQUFDLGlCQUFpQjtnQkFDaEQsZ0JBQWdCLEVBQUUsV0FBVyxDQUFDLGdCQUFnQjtnQkFDOUMsVUFBVSxFQUFFLFdBQVcsQ0FBQyxVQUFVO2dCQUNsQyxPQUFPLEVBQUUsRUFBRSxFQUFFLG1DQUFtQzthQUNqRCxDQUFDO1FBQ0osQ0FBQztRQUVELDBEQUEwRDtRQUMxRCxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDaEMsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxDQUFDO1FBRTFFLE9BQU87WUFDTCxNQUFNO1lBQ04sUUFBUSxFQUFFO2dCQUNSLElBQUksRUFBRSxRQUFRLEdBQUcsR0FBRztnQkFDcEIsTUFBTSxFQUFFLFFBQVEsR0FBRyxHQUFHO2FBQ3ZCO1lBQ0QsV0FBVyxFQUFFO2dCQUNYLFFBQVEsRUFBRSxRQUFRLENBQUMsUUFBUTtnQkFDM0IsU0FBUyxFQUFFLFFBQVEsQ0FBQyxTQUFTO2dCQUM3QixRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVE7Z0JBQzNCLEdBQUcsRUFBRSxRQUFRLENBQUMsR0FBRzthQUNsQjtZQUNELGlCQUFpQixFQUFFLENBQUM7WUFDcEIsaUJBQWlCLEVBQUUsQ0FBQztZQUNwQixnQkFBZ0IsRUFBRSxDQUFDO1lBQ25CLFVBQVUsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxFQUFFO1lBQ2xGLE9BQU8sRUFBRSxFQUFFO1NBQ1osQ0FBQztJQUNKLENBQUM7SUFFTyxLQUFLLENBQUMsaUJBQWlCO1FBUTdCLCtDQUErQztRQUMvQyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ2pELE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3RGLE9BQU87Z0JBQ0wsU0FBUyxFQUFFLFVBQVUsQ0FBQyxTQUFTO2dCQUMvQixhQUFhLEVBQUUsVUFBVSxDQUFDLGFBQWE7Z0JBQ3ZDLFVBQVUsRUFBRSxVQUFVLENBQUMsVUFBVTtnQkFDakMsWUFBWSxFQUFFLFVBQVUsQ0FBQyxZQUFZO2dCQUNyQyxTQUFTLEVBQUUsVUFBVSxDQUFDLFNBQVM7YUFDaEMsQ0FBQztRQUNKLENBQUM7UUFFRCwyQ0FBMkM7UUFDM0MsT0FBTztZQUNMLFNBQVMsRUFBRSxDQUFDO1lBQ1osYUFBYSxFQUFFLENBQUM7WUFDaEIsVUFBVSxFQUFFLENBQUM7WUFDYixZQUFZLEVBQUUsR0FBRztZQUNqQixTQUFTLEVBQUUsQ0FBQztTQUNiLENBQUM7SUFDSixDQUFDO0lBRU8sS0FBSyxDQUFDLGVBQWU7UUFjM0IsK0NBQStDO1FBQy9DLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDakQsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDbEYsT0FBTztnQkFDTCxnQkFBZ0IsRUFBRSxRQUFRLENBQUMsZ0JBQWdCO2dCQUMzQyxZQUFZLEVBQUUsUUFBUSxDQUFDLFlBQVk7Z0JBQ25DLFNBQVMsRUFBRSxRQUFRLENBQUMsU0FBUztnQkFDN0IsV0FBVyxFQUFFLFFBQVEsQ0FBQyxXQUFXO2dCQUNqQyxZQUFZLEVBQUUsUUFBUSxDQUFDLFlBQVk7Z0JBQ25DLFVBQVUsRUFBRSxRQUFRLENBQUMsVUFBVTtnQkFDL0IsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVO2dCQUMvQixhQUFhLEVBQUUsUUFBUSxDQUFDLGFBQWE7YUFDdEMsQ0FBQztRQUNKLENBQUM7UUFFRCwyQ0FBMkM7UUFDM0MsT0FBTztZQUNMLGdCQUFnQixFQUFFLENBQUM7WUFDbkIsWUFBWSxFQUFFLENBQUM7WUFDZixTQUFTLEVBQUUsQ0FBQztZQUNaLFdBQVcsRUFBRSxDQUFDO1lBQ2QsWUFBWSxFQUFFLENBQUM7WUFDZixVQUFVLEVBQUUsRUFBRTtZQUNkLFVBQVUsRUFBRSxFQUFFO1NBQ2YsQ0FBQztJQUNKLENBQUM7SUFFTyxLQUFLLENBQUMsY0FBYztRQWMxQixpREFBaUQ7UUFDakQsT0FBTztZQUNMLE9BQU8sRUFBRSxDQUFDO1lBQ1YsTUFBTSxFQUFFLENBQUM7WUFDVCxNQUFNLEVBQUUsQ0FBQztZQUNULFFBQVEsRUFBRSxDQUFDO1lBQ1gsS0FBSyxFQUFFLEVBQUU7U0FDVixDQUFDO0lBQ0osQ0FBQztJQUVPLEtBQUssQ0FBQyxpQkFBaUI7UUFhN0IsTUFBTSxRQUFRLEdBSVQsRUFBRSxDQUFDO1FBRVIsbUJBQW1CO1FBQ25CLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDN0MsUUFBUSxDQUFDLElBQUksQ0FBQztnQkFDWixJQUFJLEVBQUUsa0JBQWtCO2dCQUN4QixNQUFNLEVBQUUsU0FBUzthQUNsQixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQscUJBQXFCO1FBQ3JCLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDOUMsUUFBUSxDQUFDLElBQUksQ0FBQztnQkFDWixJQUFJLEVBQUUsY0FBYztnQkFDcEIsTUFBTSxFQUFFLFNBQVM7YUFDbEIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELG1CQUFtQjtRQUNuQixJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQzVDLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ1osSUFBSSxFQUFFLFlBQVk7Z0JBQ2xCLE1BQU0sRUFBRSxTQUFTO2FBQ2xCLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCxrQkFBa0I7UUFDbEIsUUFBUSxDQUFDLElBQUksQ0FBQztZQUNaLElBQUksRUFBRSxXQUFXO1lBQ2pCLE1BQU0sRUFBRSxTQUFTO1NBQ2xCLENBQUMsQ0FBQztRQUVILE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLFNBQVMsQ0FBQyxDQUFDO1FBRTVELE9BQU87WUFDTCxPQUFPO1lBQ1AsUUFBUTtZQUNSLE1BQU0sRUFBRTtnQkFDTjtvQkFDRSxJQUFJLEVBQUUsY0FBYztvQkFDcEIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLEdBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsRUFBRSxHQUFHLEdBQUcsQ0FBQztvQkFDdEUsT0FBTyxFQUFFLDRCQUE0QjtpQkFDdEM7YUFDRjtTQUNGLENBQUM7SUFDSixDQUFDO0NBQ0YifQ==
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Log level for security events
3
+ */
4
+ export declare enum SecurityLogLevel {
5
+ INFO = "info",
6
+ WARN = "warn",
7
+ ERROR = "error",
8
+ CRITICAL = "critical"
9
+ }
10
+ /**
11
+ * Security event types for categorization
12
+ */
13
+ export declare enum SecurityEventType {
14
+ AUTHENTICATION = "authentication",
15
+ ACCESS_CONTROL = "access_control",
16
+ EMAIL_VALIDATION = "email_validation",
17
+ EMAIL_PROCESSING = "email_processing",
18
+ EMAIL_FORWARDING = "email_forwarding",
19
+ EMAIL_DELIVERY = "email_delivery",
20
+ DKIM = "dkim",
21
+ SPF = "spf",
22
+ DMARC = "dmarc",
23
+ RATE_LIMIT = "rate_limit",
24
+ RATE_LIMITING = "rate_limiting",
25
+ SPAM = "spam",
26
+ MALWARE = "malware",
27
+ CONNECTION = "connection",
28
+ DATA_EXPOSURE = "data_exposure",
29
+ CONFIGURATION = "configuration",
30
+ IP_REPUTATION = "ip_reputation",
31
+ REJECTED_CONNECTION = "rejected_connection"
32
+ }
33
+ /**
34
+ * Security event interface
35
+ */
36
+ export interface ISecurityEvent {
37
+ timestamp: number;
38
+ level: SecurityLogLevel;
39
+ type: SecurityEventType;
40
+ message: string;
41
+ details?: any;
42
+ ipAddress?: string;
43
+ userId?: string;
44
+ sessionId?: string;
45
+ emailId?: string;
46
+ domain?: string;
47
+ action?: string;
48
+ result?: string;
49
+ success?: boolean;
50
+ }
51
+ /**
52
+ * Security logger for enhanced security monitoring
53
+ */
54
+ export declare class SecurityLogger {
55
+ private static instance;
56
+ private securityEvents;
57
+ private maxEventHistory;
58
+ private enableNotifications;
59
+ private constructor();
60
+ /**
61
+ * Get singleton instance
62
+ */
63
+ static getInstance(options?: {
64
+ maxEventHistory?: number;
65
+ enableNotifications?: boolean;
66
+ }): SecurityLogger;
67
+ /**
68
+ * Log a security event
69
+ * @param event The security event to log
70
+ */
71
+ logEvent(event: Omit<ISecurityEvent, 'timestamp'>): void;
72
+ /**
73
+ * Get recent security events
74
+ * @param limit Maximum number of events to return
75
+ * @param filter Filter for specific event types
76
+ * @returns Recent security events
77
+ */
78
+ getRecentEvents(limit?: number, filter?: {
79
+ level?: SecurityLogLevel;
80
+ type?: SecurityEventType;
81
+ fromTimestamp?: number;
82
+ toTimestamp?: number;
83
+ }): ISecurityEvent[];
84
+ /**
85
+ * Get events by security level
86
+ * @param level The security level to filter by
87
+ * @param limit Maximum number of events to return
88
+ * @returns Security events matching the level
89
+ */
90
+ getEventsByLevel(level: SecurityLogLevel, limit?: number): ISecurityEvent[];
91
+ /**
92
+ * Get events by security type
93
+ * @param type The event type to filter by
94
+ * @param limit Maximum number of events to return
95
+ * @returns Security events matching the type
96
+ */
97
+ getEventsByType(type: SecurityEventType, limit?: number): ISecurityEvent[];
98
+ /**
99
+ * Get security events for a specific IP address
100
+ * @param ipAddress The IP address to filter by
101
+ * @param limit Maximum number of events to return
102
+ * @returns Security events for the IP address
103
+ */
104
+ getEventsByIP(ipAddress: string, limit?: number): ISecurityEvent[];
105
+ /**
106
+ * Get security events for a specific domain
107
+ * @param domain The domain to filter by
108
+ * @param limit Maximum number of events to return
109
+ * @returns Security events for the domain
110
+ */
111
+ getEventsByDomain(domain: string, limit?: number): ISecurityEvent[];
112
+ /**
113
+ * Send a notification for critical security events
114
+ * @param event The security event to notify about
115
+ * @private
116
+ */
117
+ private sendNotification;
118
+ /**
119
+ * Clear event history
120
+ */
121
+ clearEvents(): void;
122
+ /**
123
+ * Get statistical summary of security events
124
+ * @param timeWindow Optional time window in milliseconds
125
+ * @returns Summary of security events
126
+ */
127
+ getEventsSummary(timeWindow?: number): {
128
+ total: number;
129
+ byLevel: Record<SecurityLogLevel, number>;
130
+ byType: Record<SecurityEventType, number>;
131
+ topIPs: Array<{
132
+ ip: string;
133
+ count: number;
134
+ }>;
135
+ topDomains: Array<{
136
+ domain: string;
137
+ count: number;
138
+ }>;
139
+ };
140
+ }
@@ -1,5 +1,81 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import * as authInterfaces from '../data/auth.js';
3
+ export interface IConfigData {
4
+ system: {
5
+ baseDir: string;
6
+ dataDir: string;
7
+ publicIp: string | null;
8
+ proxyIps: string[];
9
+ uptime: number;
10
+ storageBackend: 'filesystem' | 'custom' | 'memory';
11
+ storagePath: string | null;
12
+ };
13
+ smartProxy: {
14
+ enabled: boolean;
15
+ routeCount: number;
16
+ acme: {
17
+ enabled: boolean;
18
+ accountEmail: string;
19
+ useProduction: boolean;
20
+ autoRenew: boolean;
21
+ renewThresholdDays: number;
22
+ } | null;
23
+ };
24
+ email: {
25
+ enabled: boolean;
26
+ ports: number[];
27
+ portMapping: Record<string, number> | null;
28
+ hostname: string | null;
29
+ domains: string[];
30
+ emailRouteCount: number;
31
+ receivedEmailsPath: string | null;
32
+ };
33
+ dns: {
34
+ enabled: boolean;
35
+ port: number;
36
+ nsDomains: string[];
37
+ scopes: string[];
38
+ recordCount: number;
39
+ records: Array<{
40
+ name: string;
41
+ type: string;
42
+ value: string;
43
+ ttl?: number;
44
+ }>;
45
+ dnsChallenge: boolean;
46
+ };
47
+ tls: {
48
+ contactEmail: string | null;
49
+ domain: string | null;
50
+ source: 'acme' | 'static' | 'none';
51
+ certPath: string | null;
52
+ keyPath: string | null;
53
+ };
54
+ cache: {
55
+ enabled: boolean;
56
+ storagePath: string | null;
57
+ dbName: string | null;
58
+ defaultTTLDays: number;
59
+ cleanupIntervalHours: number;
60
+ ttlConfig: Record<string, number>;
61
+ };
62
+ radius: {
63
+ enabled: boolean;
64
+ authPort: number | null;
65
+ acctPort: number | null;
66
+ bindAddress: string | null;
67
+ clientCount: number;
68
+ vlanDefaultVlan: number | null;
69
+ vlanAllowUnknownMacs: boolean | null;
70
+ vlanMappingCount: number;
71
+ };
72
+ remoteIngress: {
73
+ enabled: boolean;
74
+ tunnelPort: number | null;
75
+ hubDomain: string | null;
76
+ tlsConfigured: boolean;
77
+ };
78
+ }
3
79
  export interface IReq_GetConfiguration extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_GetConfiguration> {
4
80
  method: 'getConfiguration';
5
81
  request: {
@@ -7,7 +83,7 @@ export interface IReq_GetConfiguration extends plugins.typedrequestInterfaces.im
7
83
  section?: string;
8
84
  };
9
85
  response: {
10
- config: any;
86
+ config: IConfigData;
11
87
  section?: string;
12
88
  };
13
89
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '8.1.0',
6
+ version: '9.1.0',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfd2ViLzAwX2NvbW1pdGluZm9fZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRztJQUN4QixJQUFJLEVBQUUsc0JBQXNCO0lBQzVCLE9BQU8sRUFBRSxPQUFPO0lBQ2hCLFdBQVcsRUFBRSwwRUFBMEU7Q0FDeEYsQ0FBQSJ9
@@ -15,7 +15,7 @@ export interface IStatsState {
15
15
  error: string | null;
16
16
  }
17
17
  export interface IConfigState {
18
- config: any | null;
18
+ config: interfaces.requests.IConfigData | null;
19
19
  isLoading: boolean;
20
20
  error: string | null;
21
21
  }