@serve.zone/dcrouter 11.0.4 → 11.0.5

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 (118) hide show
  1. package/dist_serve/bundle.js +1 -1
  2. package/package.json +1 -1
  3. package/ts/00_commitinfo_data.ts +1 -1
  4. package/ts_web/00_commitinfo_data.ts +1 -1
  5. package/dist_ts/00_commitinfo_data.d.ts +0 -8
  6. package/dist_ts/00_commitinfo_data.js +0 -9
  7. package/dist_ts/cache/classes.cache.cleaner.d.ts +0 -47
  8. package/dist_ts/cache/classes.cache.cleaner.js +0 -130
  9. package/dist_ts/cache/documents/classes.cached.email.d.ts +0 -125
  10. package/dist_ts/cache/documents/classes.cached.email.js +0 -337
  11. package/dist_ts/cache/documents/classes.cached.ip.reputation.d.ts +0 -119
  12. package/dist_ts/cache/documents/classes.cached.ip.reputation.js +0 -323
  13. package/dist_ts/cache/documents/index.d.ts +0 -2
  14. package/dist_ts/cache/documents/index.js +0 -3
  15. package/dist_ts/cache/index.d.ts +0 -4
  16. package/dist_ts/cache/index.js +0 -7
  17. package/dist_ts/classes.cert-provision-scheduler.d.ts +0 -53
  18. package/dist_ts/classes.cert-provision-scheduler.js +0 -110
  19. package/dist_ts/classes.dcrouter.d.ts +0 -337
  20. package/dist_ts/classes.dcrouter.js +0 -1405
  21. package/dist_ts/classes.storage-cert-manager.d.ts +0 -18
  22. package/dist_ts/classes.storage-cert-manager.js +0 -43
  23. package/dist_ts/config/classes.api-token-manager.d.ts +0 -46
  24. package/dist_ts/config/classes.api-token-manager.js +0 -150
  25. package/dist_ts/config/classes.route-config-manager.d.ts +0 -35
  26. package/dist_ts/config/classes.route-config-manager.js +0 -231
  27. package/dist_ts/config/index.d.ts +0 -3
  28. package/dist_ts/config/index.js +0 -5
  29. package/dist_ts/config/validator.d.ts +0 -104
  30. package/dist_ts/config/validator.js +0 -152
  31. package/dist_ts/errors/base.errors.d.ts +0 -224
  32. package/dist_ts/errors/base.errors.js +0 -320
  33. package/dist_ts/errors/error-handler.d.ts +0 -98
  34. package/dist_ts/errors/error-handler.js +0 -282
  35. package/dist_ts/errors/error.codes.d.ts +0 -115
  36. package/dist_ts/errors/error.codes.js +0 -136
  37. package/dist_ts/errors/index.d.ts +0 -54
  38. package/dist_ts/errors/index.js +0 -136
  39. package/dist_ts/errors/reputation.errors.d.ts +0 -183
  40. package/dist_ts/errors/reputation.errors.js +0 -292
  41. package/dist_ts/index.d.ts +0 -7
  42. package/dist_ts/index.js +0 -11
  43. package/dist_ts/logger.d.ts +0 -21
  44. package/dist_ts/logger.js +0 -81
  45. package/dist_ts/monitoring/classes.metricscache.d.ts +0 -32
  46. package/dist_ts/monitoring/classes.metricscache.js +0 -63
  47. package/dist_ts/monitoring/classes.metricsmanager.d.ts +0 -178
  48. package/dist_ts/monitoring/classes.metricsmanager.js +0 -642
  49. package/dist_ts/monitoring/index.d.ts +0 -1
  50. package/dist_ts/monitoring/index.js +0 -2
  51. package/dist_ts/opsserver/classes.opsserver.d.ts +0 -37
  52. package/dist_ts/opsserver/classes.opsserver.js +0 -85
  53. package/dist_ts/opsserver/handlers/admin.handler.d.ts +0 -31
  54. package/dist_ts/opsserver/handlers/admin.handler.js +0 -180
  55. package/dist_ts/opsserver/handlers/api-token.handler.d.ts +0 -6
  56. package/dist_ts/opsserver/handlers/api-token.handler.js +0 -62
  57. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +0 -32
  58. package/dist_ts/opsserver/handlers/certificate.handler.js +0 -421
  59. package/dist_ts/opsserver/handlers/config.handler.d.ts +0 -7
  60. package/dist_ts/opsserver/handlers/config.handler.js +0 -192
  61. package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +0 -30
  62. package/dist_ts/opsserver/handlers/email-ops.handler.js +0 -227
  63. package/dist_ts/opsserver/handlers/index.d.ts +0 -11
  64. package/dist_ts/opsserver/handlers/index.js +0 -12
  65. package/dist_ts/opsserver/handlers/logs.handler.d.ts +0 -25
  66. package/dist_ts/opsserver/handlers/logs.handler.js +0 -256
  67. package/dist_ts/opsserver/handlers/radius.handler.d.ts +0 -6
  68. package/dist_ts/opsserver/handlers/radius.handler.js +0 -295
  69. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +0 -6
  70. package/dist_ts/opsserver/handlers/remoteingress.handler.js +0 -156
  71. package/dist_ts/opsserver/handlers/route-management.handler.d.ts +0 -14
  72. package/dist_ts/opsserver/handlers/route-management.handler.js +0 -117
  73. package/dist_ts/opsserver/handlers/security.handler.d.ts +0 -9
  74. package/dist_ts/opsserver/handlers/security.handler.js +0 -231
  75. package/dist_ts/opsserver/handlers/stats.handler.d.ts +0 -11
  76. package/dist_ts/opsserver/handlers/stats.handler.js +0 -399
  77. package/dist_ts/opsserver/helpers/guards.d.ts +0 -27
  78. package/dist_ts/opsserver/helpers/guards.js +0 -43
  79. package/dist_ts/opsserver/index.d.ts +0 -1
  80. package/dist_ts/opsserver/index.js +0 -2
  81. package/dist_ts/paths.d.ts +0 -26
  82. package/dist_ts/paths.js +0 -45
  83. package/dist_ts/plugins.d.ts +0 -79
  84. package/dist_ts/plugins.js +0 -113
  85. package/dist_ts/radius/classes.accounting.manager.d.ts +0 -218
  86. package/dist_ts/radius/classes.accounting.manager.js +0 -417
  87. package/dist_ts/radius/classes.radius.server.d.ts +0 -171
  88. package/dist_ts/radius/classes.radius.server.js +0 -385
  89. package/dist_ts/radius/classes.vlan.manager.d.ts +0 -128
  90. package/dist_ts/radius/classes.vlan.manager.js +0 -279
  91. package/dist_ts/radius/index.d.ts +0 -13
  92. package/dist_ts/radius/index.js +0 -14
  93. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +0 -82
  94. package/dist_ts/remoteingress/classes.remoteingress-manager.js +0 -227
  95. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +0 -59
  96. package/dist_ts/remoteingress/classes.tunnel-manager.js +0 -165
  97. package/dist_ts/remoteingress/index.d.ts +0 -2
  98. package/dist_ts/remoteingress/index.js +0 -3
  99. package/dist_ts/security/classes.contentscanner.d.ts +0 -164
  100. package/dist_ts/security/classes.contentscanner.js +0 -642
  101. package/dist_ts/security/classes.ipreputationchecker.d.ts +0 -160
  102. package/dist_ts/security/classes.ipreputationchecker.js +0 -537
  103. package/dist_ts/security/classes.securitylogger.d.ts +0 -144
  104. package/dist_ts/security/classes.securitylogger.js +0 -233
  105. package/dist_ts/security/index.d.ts +0 -3
  106. package/dist_ts/security/index.js +0 -4
  107. package/dist_ts/sms/classes.smsservice.d.ts +0 -15
  108. package/dist_ts/sms/classes.smsservice.js +0 -72
  109. package/dist_ts/sms/config/sms.config.d.ts +0 -93
  110. package/dist_ts/sms/config/sms.config.js +0 -2
  111. package/dist_ts/sms/config/sms.schema.d.ts +0 -5
  112. package/dist_ts/sms/config/sms.schema.js +0 -121
  113. package/dist_ts/sms/index.d.ts +0 -1
  114. package/dist_ts/sms/index.js +0 -2
  115. package/dist_ts/storage/classes.storagemanager.d.ts +0 -83
  116. package/dist_ts/storage/classes.storagemanager.js +0 -350
  117. package/dist_ts/storage/index.d.ts +0 -1
  118. package/dist_ts/storage/index.js +0 -3
@@ -1,417 +0,0 @@
1
- import * as plugins from '../plugins.js';
2
- import { logger } from '../logger.js';
3
- /**
4
- * Manages RADIUS accounting data including:
5
- * - Session tracking (start/stop/interim)
6
- * - Data usage tracking (bytes in/out)
7
- * - Session history and retention
8
- * - Billing reports and summaries
9
- */
10
- export class AccountingManager {
11
- activeSessions = new Map();
12
- config;
13
- storageManager;
14
- // Counters for statistics
15
- stats = {
16
- totalSessionsStarted: 0,
17
- totalSessionsStopped: 0,
18
- totalInputBytes: 0,
19
- totalOutputBytes: 0,
20
- interimUpdatesReceived: 0,
21
- };
22
- constructor(config, storageManager) {
23
- this.config = {
24
- storagePrefix: config?.storagePrefix ?? '/radius/accounting',
25
- retentionDays: config?.retentionDays ?? 30,
26
- detailedLogging: config?.detailedLogging ?? false,
27
- maxActiveSessions: config?.maxActiveSessions ?? 10000,
28
- };
29
- this.storageManager = storageManager;
30
- }
31
- /**
32
- * Initialize the accounting manager
33
- */
34
- async initialize() {
35
- if (this.storageManager) {
36
- await this.loadActiveSessions();
37
- }
38
- logger.log('info', `AccountingManager initialized with ${this.activeSessions.size} active sessions`);
39
- }
40
- /**
41
- * Handle accounting start request
42
- */
43
- async handleAccountingStart(data) {
44
- const now = Date.now();
45
- const session = {
46
- sessionId: data.sessionId,
47
- username: data.username,
48
- macAddress: data.macAddress,
49
- nasIpAddress: data.nasIpAddress,
50
- nasPort: data.nasPort,
51
- nasPortType: data.nasPortType,
52
- nasIdentifier: data.nasIdentifier,
53
- vlanId: data.vlanId,
54
- framedIpAddress: data.framedIpAddress,
55
- calledStationId: data.calledStationId,
56
- callingStationId: data.callingStationId,
57
- serviceType: data.serviceType,
58
- startTime: now,
59
- endTime: 0,
60
- lastUpdateTime: now,
61
- status: 'active',
62
- inputOctets: 0,
63
- outputOctets: 0,
64
- inputPackets: 0,
65
- outputPackets: 0,
66
- sessionTime: 0,
67
- };
68
- // Check if we're at capacity
69
- if (this.activeSessions.size >= this.config.maxActiveSessions) {
70
- // Remove oldest session
71
- const oldest = this.findOldestSession();
72
- if (oldest) {
73
- await this.evictSession(oldest);
74
- }
75
- }
76
- this.activeSessions.set(data.sessionId, session);
77
- this.stats.totalSessionsStarted++;
78
- if (this.config.detailedLogging) {
79
- logger.log('info', `Accounting Start: session=${data.sessionId}, user=${data.username}, NAS=${data.nasIpAddress}`);
80
- }
81
- // Persist session
82
- if (this.storageManager) {
83
- await this.persistSession(session);
84
- }
85
- }
86
- /**
87
- * Handle accounting interim update request
88
- */
89
- async handleAccountingUpdate(data) {
90
- const session = this.activeSessions.get(data.sessionId);
91
- if (!session) {
92
- logger.log('warn', `Interim update for unknown session: ${data.sessionId}`);
93
- return;
94
- }
95
- // Update session metrics
96
- if (data.inputOctets !== undefined) {
97
- session.inputOctets = data.inputOctets;
98
- }
99
- if (data.outputOctets !== undefined) {
100
- session.outputOctets = data.outputOctets;
101
- }
102
- if (data.inputPackets !== undefined) {
103
- session.inputPackets = data.inputPackets;
104
- }
105
- if (data.outputPackets !== undefined) {
106
- session.outputPackets = data.outputPackets;
107
- }
108
- if (data.sessionTime !== undefined) {
109
- session.sessionTime = data.sessionTime;
110
- }
111
- session.lastUpdateTime = Date.now();
112
- this.stats.interimUpdatesReceived++;
113
- if (this.config.detailedLogging) {
114
- logger.log('debug', `Accounting Interim: session=${data.sessionId}, in=${data.inputOctets}, out=${data.outputOctets}`);
115
- }
116
- // Update persisted session
117
- if (this.storageManager) {
118
- await this.persistSession(session);
119
- }
120
- }
121
- /**
122
- * Handle accounting stop request
123
- */
124
- async handleAccountingStop(data) {
125
- const session = this.activeSessions.get(data.sessionId);
126
- if (!session) {
127
- logger.log('warn', `Stop for unknown session: ${data.sessionId}`);
128
- return;
129
- }
130
- // Update final metrics
131
- if (data.inputOctets !== undefined) {
132
- session.inputOctets = data.inputOctets;
133
- }
134
- if (data.outputOctets !== undefined) {
135
- session.outputOctets = data.outputOctets;
136
- }
137
- if (data.inputPackets !== undefined) {
138
- session.inputPackets = data.inputPackets;
139
- }
140
- if (data.outputPackets !== undefined) {
141
- session.outputPackets = data.outputPackets;
142
- }
143
- if (data.sessionTime !== undefined) {
144
- session.sessionTime = data.sessionTime;
145
- }
146
- session.endTime = Date.now();
147
- session.lastUpdateTime = session.endTime;
148
- session.status = 'stopped';
149
- session.terminateCause = data.terminateCause;
150
- // Update global stats
151
- this.stats.totalSessionsStopped++;
152
- this.stats.totalInputBytes += session.inputOctets;
153
- this.stats.totalOutputBytes += session.outputOctets;
154
- if (this.config.detailedLogging) {
155
- logger.log('info', `Accounting Stop: session=${data.sessionId}, duration=${session.sessionTime}s, in=${session.inputOctets}, out=${session.outputOctets}`);
156
- }
157
- // Archive the session
158
- if (this.storageManager) {
159
- await this.archiveSession(session);
160
- }
161
- // Remove from active sessions
162
- this.activeSessions.delete(data.sessionId);
163
- }
164
- /**
165
- * Get an active session by ID
166
- */
167
- getSession(sessionId) {
168
- return this.activeSessions.get(sessionId);
169
- }
170
- /**
171
- * Get all active sessions
172
- */
173
- getActiveSessions() {
174
- return Array.from(this.activeSessions.values());
175
- }
176
- /**
177
- * Get active sessions by username
178
- */
179
- getSessionsByUsername(username) {
180
- return Array.from(this.activeSessions.values()).filter(s => s.username === username);
181
- }
182
- /**
183
- * Get active sessions by NAS IP
184
- */
185
- getSessionsByNas(nasIpAddress) {
186
- return Array.from(this.activeSessions.values()).filter(s => s.nasIpAddress === nasIpAddress);
187
- }
188
- /**
189
- * Get active sessions by VLAN
190
- */
191
- getSessionsByVlan(vlanId) {
192
- return Array.from(this.activeSessions.values()).filter(s => s.vlanId === vlanId);
193
- }
194
- /**
195
- * Get accounting summary for a time period
196
- */
197
- async getSummary(startTime, endTime) {
198
- // Get archived sessions for the time period
199
- const archivedSessions = await this.getArchivedSessions(startTime, endTime);
200
- // Combine with active sessions that started within the period
201
- const activeSessions = Array.from(this.activeSessions.values()).filter(s => s.startTime >= startTime && s.startTime <= endTime);
202
- const allSessions = [...archivedSessions, ...activeSessions];
203
- // Calculate summary
204
- let totalInputBytes = 0;
205
- let totalOutputBytes = 0;
206
- let totalSessionTime = 0;
207
- const uniqueUsers = new Set();
208
- const sessionsByVlan = {};
209
- const userTraffic = {};
210
- for (const session of allSessions) {
211
- totalInputBytes += session.inputOctets;
212
- totalOutputBytes += session.outputOctets;
213
- totalSessionTime += session.sessionTime;
214
- uniqueUsers.add(session.username);
215
- if (session.vlanId !== undefined) {
216
- sessionsByVlan[session.vlanId] = (sessionsByVlan[session.vlanId] || 0) + 1;
217
- }
218
- const userBytes = session.inputOctets + session.outputOctets;
219
- userTraffic[session.username] = (userTraffic[session.username] || 0) + userBytes;
220
- }
221
- // Top users by traffic
222
- const topUsersByTraffic = Object.entries(userTraffic)
223
- .sort((a, b) => b[1] - a[1])
224
- .slice(0, 10)
225
- .map(([username, totalBytes]) => ({ username, totalBytes }));
226
- return {
227
- periodStart: startTime,
228
- periodEnd: endTime,
229
- totalSessions: allSessions.length,
230
- activeSessions: activeSessions.length,
231
- totalInputBytes,
232
- totalOutputBytes,
233
- totalSessionTime,
234
- averageSessionDuration: allSessions.length > 0 ? totalSessionTime / allSessions.length : 0,
235
- uniqueUsers: uniqueUsers.size,
236
- sessionsByVlan,
237
- topUsersByTraffic,
238
- };
239
- }
240
- /**
241
- * Get statistics
242
- */
243
- getStats() {
244
- return {
245
- activeSessions: this.activeSessions.size,
246
- ...this.stats,
247
- };
248
- }
249
- /**
250
- * Disconnect a session (admin action)
251
- */
252
- async disconnectSession(sessionId, reason = 'AdminReset') {
253
- const session = this.activeSessions.get(sessionId);
254
- if (!session) {
255
- return false;
256
- }
257
- await this.handleAccountingStop({
258
- sessionId,
259
- terminateCause: reason,
260
- sessionTime: Math.floor((Date.now() - session.startTime) / 1000),
261
- });
262
- return true;
263
- }
264
- /**
265
- * Clean up old archived sessions based on retention policy
266
- */
267
- async cleanupOldSessions() {
268
- if (!this.storageManager) {
269
- return 0;
270
- }
271
- const cutoffTime = Date.now() - this.config.retentionDays * 24 * 60 * 60 * 1000;
272
- let deletedCount = 0;
273
- try {
274
- const keys = await this.storageManager.list(`${this.config.storagePrefix}/archive/`);
275
- for (const key of keys) {
276
- try {
277
- const session = await this.storageManager.getJSON(key);
278
- if (session && session.endTime > 0 && session.endTime < cutoffTime) {
279
- await this.storageManager.delete(key);
280
- deletedCount++;
281
- }
282
- }
283
- catch (error) {
284
- // Ignore individual errors
285
- }
286
- }
287
- if (deletedCount > 0) {
288
- logger.log('info', `Cleaned up ${deletedCount} old accounting sessions`);
289
- }
290
- }
291
- catch (error) {
292
- logger.log('error', `Failed to cleanup old sessions: ${error.message}`);
293
- }
294
- return deletedCount;
295
- }
296
- /**
297
- * Find the oldest active session
298
- */
299
- findOldestSession() {
300
- let oldestTime = Infinity;
301
- let oldestSessionId = null;
302
- for (const [sessionId, session] of this.activeSessions) {
303
- if (session.lastUpdateTime < oldestTime) {
304
- oldestTime = session.lastUpdateTime;
305
- oldestSessionId = sessionId;
306
- }
307
- }
308
- return oldestSessionId;
309
- }
310
- /**
311
- * Evict a session from memory
312
- */
313
- async evictSession(sessionId) {
314
- const session = this.activeSessions.get(sessionId);
315
- if (session) {
316
- session.status = 'terminated';
317
- session.terminateCause = 'SessionEvicted';
318
- session.endTime = Date.now();
319
- if (this.storageManager) {
320
- await this.archiveSession(session);
321
- }
322
- this.activeSessions.delete(sessionId);
323
- logger.log('warn', `Evicted session ${sessionId} due to capacity limit`);
324
- }
325
- }
326
- /**
327
- * Load active sessions from storage
328
- */
329
- async loadActiveSessions() {
330
- if (!this.storageManager) {
331
- return;
332
- }
333
- try {
334
- const keys = await this.storageManager.list(`${this.config.storagePrefix}/active/`);
335
- for (const key of keys) {
336
- try {
337
- const session = await this.storageManager.getJSON(key);
338
- if (session && session.status === 'active') {
339
- this.activeSessions.set(session.sessionId, session);
340
- }
341
- }
342
- catch (error) {
343
- // Ignore individual errors
344
- }
345
- }
346
- }
347
- catch (error) {
348
- logger.log('warn', `Failed to load active sessions: ${error.message}`);
349
- }
350
- }
351
- /**
352
- * Persist a session to storage
353
- */
354
- async persistSession(session) {
355
- if (!this.storageManager) {
356
- return;
357
- }
358
- const key = `${this.config.storagePrefix}/active/${session.sessionId}.json`;
359
- try {
360
- await this.storageManager.setJSON(key, session);
361
- }
362
- catch (error) {
363
- logger.log('error', `Failed to persist session ${session.sessionId}: ${error.message}`);
364
- }
365
- }
366
- /**
367
- * Archive a completed session
368
- */
369
- async archiveSession(session) {
370
- if (!this.storageManager) {
371
- return;
372
- }
373
- try {
374
- // Remove from active
375
- const activeKey = `${this.config.storagePrefix}/active/${session.sessionId}.json`;
376
- await this.storageManager.delete(activeKey);
377
- // Add to archive with date-based path
378
- const date = new Date(session.endTime);
379
- const archiveKey = `${this.config.storagePrefix}/archive/${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, '0')}/${String(date.getDate()).padStart(2, '0')}/${session.sessionId}.json`;
380
- await this.storageManager.setJSON(archiveKey, session);
381
- }
382
- catch (error) {
383
- logger.log('error', `Failed to archive session ${session.sessionId}: ${error.message}`);
384
- }
385
- }
386
- /**
387
- * Get archived sessions for a time period
388
- */
389
- async getArchivedSessions(startTime, endTime) {
390
- if (!this.storageManager) {
391
- return [];
392
- }
393
- const sessions = [];
394
- try {
395
- const keys = await this.storageManager.list(`${this.config.storagePrefix}/archive/`);
396
- for (const key of keys) {
397
- try {
398
- const session = await this.storageManager.getJSON(key);
399
- if (session &&
400
- session.endTime > 0 &&
401
- session.startTime <= endTime &&
402
- session.endTime >= startTime) {
403
- sessions.push(session);
404
- }
405
- }
406
- catch (error) {
407
- // Ignore individual errors
408
- }
409
- }
410
- }
411
- catch (error) {
412
- logger.log('warn', `Failed to get archived sessions: ${error.message}`);
413
- }
414
- return sessions;
415
- }
416
- }
417
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hY2NvdW50aW5nLm1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9yYWRpdXMvY2xhc3Nlcy5hY2NvdW50aW5nLm1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQStGdEM7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLGlCQUFpQjtJQUNwQixjQUFjLEdBQW9DLElBQUksR0FBRyxFQUFFLENBQUM7SUFDNUQsTUFBTSxDQUFxQztJQUMzQyxjQUFjLENBQWtCO0lBRXhDLDBCQUEwQjtJQUNsQixLQUFLLEdBQUc7UUFDZCxvQkFBb0IsRUFBRSxDQUFDO1FBQ3ZCLG9CQUFvQixFQUFFLENBQUM7UUFDdkIsZUFBZSxFQUFFLENBQUM7UUFDbEIsZ0JBQWdCLEVBQUUsQ0FBQztRQUNuQixzQkFBc0IsRUFBRSxDQUFDO0tBQzFCLENBQUM7SUFFRixZQUFZLE1BQWlDLEVBQUUsY0FBK0I7UUFDNUUsSUFBSSxDQUFDLE1BQU0sR0FBRztZQUNaLGFBQWEsRUFBRSxNQUFNLEVBQUUsYUFBYSxJQUFJLG9CQUFvQjtZQUM1RCxhQUFhLEVBQUUsTUFBTSxFQUFFLGFBQWEsSUFBSSxFQUFFO1lBQzFDLGVBQWUsRUFBRSxNQUFNLEVBQUUsZUFBZSxJQUFJLEtBQUs7WUFDakQsaUJBQWlCLEVBQUUsTUFBTSxFQUFFLGlCQUFpQixJQUFJLEtBQUs7U0FDdEQsQ0FBQztRQUNGLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDeEIsTUFBTSxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUNsQyxDQUFDO1FBQ0QsTUFBTSxDQUFD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
@@ -1,171 +0,0 @@
1
- import type { StorageManager } from '../storage/index.js';
2
- import { VlanManager, type IMacVlanMapping, type IVlanManagerConfig } from './classes.vlan.manager.js';
3
- import { AccountingManager, type IAccountingManagerConfig } from './classes.accounting.manager.js';
4
- /**
5
- * RADIUS client (NAS) configuration
6
- */
7
- export interface IRadiusClient {
8
- /** Client name for identification */
9
- name: string;
10
- /** IP address or CIDR range */
11
- ipRange: string;
12
- /** Shared secret for this client */
13
- secret: string;
14
- /** Optional description */
15
- description?: string;
16
- /** Whether this client is enabled */
17
- enabled: boolean;
18
- }
19
- /**
20
- * RADIUS server configuration
21
- */
22
- export interface IRadiusServerConfig {
23
- /** Authentication port (default: 1812) */
24
- authPort?: number;
25
- /** Accounting port (default: 1813) */
26
- acctPort?: number;
27
- /** Bind address (default: 0.0.0.0) */
28
- bindAddress?: string;
29
- /** NAS clients configuration */
30
- clients: IRadiusClient[];
31
- /** VLAN assignment configuration */
32
- vlanAssignment?: IVlanManagerConfig & {
33
- /** Static MAC to VLAN mappings */
34
- mappings?: Array<Omit<IMacVlanMapping, 'createdAt' | 'updatedAt'>>;
35
- };
36
- /** Accounting configuration */
37
- accounting?: IAccountingManagerConfig & {
38
- /** Whether accounting is enabled */
39
- enabled: boolean;
40
- };
41
- }
42
- /**
43
- * RADIUS authentication result
44
- */
45
- export interface IRadiusAuthResult {
46
- /** Whether authentication was successful */
47
- success: boolean;
48
- /** Reject reason (if not successful) */
49
- rejectReason?: string;
50
- /** Reply message to send to client */
51
- replyMessage?: string;
52
- /** Session timeout in seconds */
53
- sessionTimeout?: number;
54
- /** Idle timeout in seconds */
55
- idleTimeout?: number;
56
- /** VLAN to assign */
57
- vlanId?: number;
58
- /** Framed IP address to assign */
59
- framedIpAddress?: string;
60
- }
61
- /**
62
- * Authentication request data from RADIUS
63
- */
64
- export interface IAuthRequestData {
65
- username: string;
66
- password?: string;
67
- nasIpAddress: string;
68
- nasPort?: number;
69
- nasPortType?: string;
70
- nasIdentifier?: string;
71
- calledStationId?: string;
72
- callingStationId?: string;
73
- serviceType?: string;
74
- framedMtu?: number;
75
- }
76
- /**
77
- * RADIUS Server wrapper that provides:
78
- * - MAC Authentication Bypass (MAB) for network devices
79
- * - VLAN assignment based on MAC address
80
- * - Accounting for session tracking and billing
81
- * - Integration with SmartProxy routing
82
- */
83
- export declare class RadiusServer {
84
- private radiusServer?;
85
- private vlanManager;
86
- private accountingManager;
87
- private config;
88
- private storageManager?;
89
- private clientSecrets;
90
- private running;
91
- private stats;
92
- constructor(config: IRadiusServerConfig, storageManager?: StorageManager);
93
- /**
94
- * Start the RADIUS server
95
- */
96
- start(): Promise<void>;
97
- /**
98
- * Stop the RADIUS server
99
- */
100
- stop(): Promise<void>;
101
- /**
102
- * Handle authentication request
103
- */
104
- private handleAuthentication;
105
- /**
106
- * Handle accounting request
107
- */
108
- private handleAccounting;
109
- /**
110
- * Perform MAC Authentication Bypass
111
- */
112
- private performMabAuthentication;
113
- /**
114
- * Extract MAC address from authentication data
115
- */
116
- private extractMacAddress;
117
- /**
118
- * Check if a string looks like a MAC address
119
- */
120
- private looksLikeMac;
121
- /**
122
- * Normalize MAC address format
123
- */
124
- private normalizeMac;
125
- /**
126
- * Build client secrets map from configuration
127
- */
128
- private buildClientSecretsMap;
129
- /**
130
- * Get default secret for unknown clients
131
- */
132
- private getDefaultSecret;
133
- /**
134
- * Add a RADIUS client
135
- */
136
- addClient(client: IRadiusClient): Promise<void>;
137
- /**
138
- * Remove a RADIUS client
139
- */
140
- removeClient(name: string): boolean;
141
- /**
142
- * Get configured clients
143
- */
144
- getClients(): IRadiusClient[];
145
- /**
146
- * Get VLAN manager for direct access to VLAN operations
147
- */
148
- getVlanManager(): VlanManager;
149
- /**
150
- * Get accounting manager for direct access to accounting operations
151
- */
152
- getAccountingManager(): AccountingManager;
153
- /**
154
- * Get server statistics
155
- */
156
- getStats(): {
157
- running: boolean;
158
- uptime: number;
159
- authRequests: number;
160
- authAccepts: number;
161
- authRejects: number;
162
- accountingRequests: number;
163
- activeSessions: number;
164
- vlanMappings: number;
165
- clients: number;
166
- };
167
- /**
168
- * Check if server is running
169
- */
170
- isRunning(): boolean;
171
- }