@serve.zone/dcrouter 11.0.44 → 11.0.46

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 (96) hide show
  1. package/dist_serve/bundle.js +1 -1
  2. package/dist_ts/cache/classes.cache.cleaner.d.ts +47 -0
  3. package/dist_ts/cache/classes.cache.cleaner.js +130 -0
  4. package/dist_ts/cache/classes.cached.document.d.ts +76 -0
  5. package/dist_ts/cache/classes.cached.document.js +100 -0
  6. package/dist_ts/cache/classes.cachedb.d.ts +60 -0
  7. package/dist_ts/cache/classes.cachedb.js +126 -0
  8. package/dist_ts/cache/documents/classes.cached.email.d.ts +125 -0
  9. package/dist_ts/cache/documents/classes.cached.email.js +337 -0
  10. package/dist_ts/cache/documents/classes.cached.ip.reputation.d.ts +119 -0
  11. package/dist_ts/cache/documents/classes.cached.ip.reputation.js +323 -0
  12. package/dist_ts/cache/documents/index.d.ts +2 -0
  13. package/dist_ts/cache/documents/index.js +3 -0
  14. package/dist_ts/cache/index.d.ts +4 -0
  15. package/dist_ts/cache/index.js +7 -0
  16. package/dist_ts/classes.cert-provision-scheduler.d.ts +53 -0
  17. package/dist_ts/classes.cert-provision-scheduler.js +110 -0
  18. package/dist_ts/classes.storage-cert-manager.d.ts +18 -0
  19. package/dist_ts/classes.storage-cert-manager.js +43 -0
  20. package/dist_ts/config/classes.api-token-manager.d.ts +46 -0
  21. package/dist_ts/config/classes.api-token-manager.js +150 -0
  22. package/dist_ts/config/classes.route-config-manager.d.ts +35 -0
  23. package/dist_ts/config/classes.route-config-manager.js +231 -0
  24. package/dist_ts/config/index.d.ts +3 -0
  25. package/dist_ts/config/index.js +5 -0
  26. package/dist_ts/config/validator.d.ts +104 -0
  27. package/dist_ts/config/validator.js +152 -0
  28. package/dist_ts/errors/base.errors.d.ts +224 -0
  29. package/dist_ts/errors/base.errors.js +320 -0
  30. package/dist_ts/errors/error.codes.d.ts +115 -0
  31. package/dist_ts/errors/error.codes.js +136 -0
  32. package/dist_ts/logger.d.ts +21 -0
  33. package/dist_ts/logger.js +81 -0
  34. package/dist_ts/monitoring/classes.metricscache.d.ts +32 -0
  35. package/dist_ts/monitoring/classes.metricscache.js +63 -0
  36. package/dist_ts/monitoring/classes.metricsmanager.d.ts +178 -0
  37. package/dist_ts/monitoring/classes.metricsmanager.js +642 -0
  38. package/dist_ts/monitoring/index.d.ts +1 -0
  39. package/dist_ts/monitoring/index.js +2 -0
  40. package/dist_ts/opsserver/classes.opsserver.d.ts +37 -0
  41. package/dist_ts/opsserver/classes.opsserver.js +85 -0
  42. package/dist_ts/opsserver/handlers/admin.handler.d.ts +31 -0
  43. package/dist_ts/opsserver/handlers/admin.handler.js +180 -0
  44. package/dist_ts/opsserver/handlers/api-token.handler.d.ts +6 -0
  45. package/dist_ts/opsserver/handlers/api-token.handler.js +62 -0
  46. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +32 -0
  47. package/dist_ts/opsserver/handlers/certificate.handler.js +421 -0
  48. package/dist_ts/opsserver/handlers/config.handler.d.ts +7 -0
  49. package/dist_ts/opsserver/handlers/config.handler.js +192 -0
  50. package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +30 -0
  51. package/dist_ts/opsserver/handlers/email-ops.handler.js +227 -0
  52. package/dist_ts/opsserver/handlers/index.d.ts +11 -0
  53. package/dist_ts/opsserver/handlers/index.js +12 -0
  54. package/dist_ts/opsserver/handlers/logs.handler.d.ts +25 -0
  55. package/dist_ts/opsserver/handlers/logs.handler.js +256 -0
  56. package/dist_ts/opsserver/handlers/radius.handler.d.ts +6 -0
  57. package/dist_ts/opsserver/handlers/radius.handler.js +295 -0
  58. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +6 -0
  59. package/dist_ts/opsserver/handlers/remoteingress.handler.js +156 -0
  60. package/dist_ts/opsserver/handlers/route-management.handler.d.ts +14 -0
  61. package/dist_ts/opsserver/handlers/route-management.handler.js +117 -0
  62. package/dist_ts/opsserver/handlers/security.handler.d.ts +9 -0
  63. package/dist_ts/opsserver/handlers/security.handler.js +231 -0
  64. package/dist_ts/opsserver/handlers/stats.handler.d.ts +11 -0
  65. package/dist_ts/opsserver/handlers/stats.handler.js +399 -0
  66. package/dist_ts/opsserver/helpers/guards.d.ts +27 -0
  67. package/dist_ts/opsserver/helpers/guards.js +43 -0
  68. package/dist_ts/opsserver/index.d.ts +1 -0
  69. package/dist_ts/opsserver/index.js +2 -0
  70. package/dist_ts/paths.d.ts +26 -0
  71. package/dist_ts/paths.js +45 -0
  72. package/dist_ts/plugins.d.ts +79 -0
  73. package/dist_ts/radius/classes.accounting.manager.d.ts +218 -0
  74. package/dist_ts/radius/classes.accounting.manager.js +417 -0
  75. package/dist_ts/radius/classes.radius.server.d.ts +171 -0
  76. package/dist_ts/radius/classes.radius.server.js +385 -0
  77. package/dist_ts/radius/classes.vlan.manager.d.ts +128 -0
  78. package/dist_ts/radius/classes.vlan.manager.js +279 -0
  79. package/dist_ts/radius/index.d.ts +13 -0
  80. package/dist_ts/radius/index.js +14 -0
  81. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +82 -0
  82. package/dist_ts/remoteingress/classes.remoteingress-manager.js +227 -0
  83. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +59 -0
  84. package/dist_ts/remoteingress/classes.tunnel-manager.js +165 -0
  85. package/dist_ts/remoteingress/index.d.ts +2 -0
  86. package/dist_ts/remoteingress/index.js +3 -0
  87. package/dist_ts/security/classes.securitylogger.d.ts +144 -0
  88. package/dist_ts/security/classes.securitylogger.js +233 -0
  89. package/dist_ts/storage/classes.storagemanager.d.ts +83 -0
  90. package/dist_ts/storage/classes.storagemanager.js +350 -0
  91. package/dist_ts/storage/index.d.ts +1 -0
  92. package/dist_ts/storage/index.js +3 -0
  93. package/dist_ts_web/00_commitinfo_data.js +1 -1
  94. package/package.json +2 -2
  95. package/ts/00_commitinfo_data.ts +1 -1
  96. package/ts_web/00_commitinfo_data.ts +1 -1
@@ -0,0 +1,171 @@
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
+ }
@@ -0,0 +1,385 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { logger } from '../logger.js';
3
+ import { VlanManager } from './classes.vlan.manager.js';
4
+ import { AccountingManager } from './classes.accounting.manager.js';
5
+ /**
6
+ * RADIUS Server wrapper that provides:
7
+ * - MAC Authentication Bypass (MAB) for network devices
8
+ * - VLAN assignment based on MAC address
9
+ * - Accounting for session tracking and billing
10
+ * - Integration with SmartProxy routing
11
+ */
12
+ export class RadiusServer {
13
+ radiusServer;
14
+ vlanManager;
15
+ accountingManager;
16
+ config;
17
+ storageManager;
18
+ clientSecrets = new Map();
19
+ running = false;
20
+ // Statistics
21
+ stats = {
22
+ authRequests: 0,
23
+ authAccepts: 0,
24
+ authRejects: 0,
25
+ accountingRequests: 0,
26
+ startTime: 0,
27
+ };
28
+ constructor(config, storageManager) {
29
+ this.config = {
30
+ authPort: config.authPort ?? 1812,
31
+ acctPort: config.acctPort ?? 1813,
32
+ bindAddress: config.bindAddress ?? '0.0.0.0',
33
+ ...config,
34
+ };
35
+ this.storageManager = storageManager;
36
+ // Initialize VLAN manager
37
+ this.vlanManager = new VlanManager(config.vlanAssignment, storageManager);
38
+ // Initialize accounting manager
39
+ this.accountingManager = new AccountingManager(config.accounting, storageManager);
40
+ }
41
+ /**
42
+ * Start the RADIUS server
43
+ */
44
+ async start() {
45
+ if (this.running) {
46
+ logger.log('warn', 'RADIUS server is already running');
47
+ return;
48
+ }
49
+ logger.log('info', `Starting RADIUS server on ${this.config.bindAddress}:${this.config.authPort} (auth) and ${this.config.acctPort} (acct)`);
50
+ // Initialize managers
51
+ await this.vlanManager.initialize();
52
+ await this.accountingManager.initialize();
53
+ // Import static VLAN mappings if provided
54
+ if (this.config.vlanAssignment?.mappings) {
55
+ await this.vlanManager.importMappings(this.config.vlanAssignment.mappings);
56
+ }
57
+ // Build client secrets map
58
+ this.buildClientSecretsMap();
59
+ // Create the RADIUS server
60
+ this.radiusServer = new plugins.smartradius.RadiusServer({
61
+ authPort: this.config.authPort,
62
+ acctPort: this.config.acctPort,
63
+ bindAddress: this.config.bindAddress,
64
+ defaultSecret: this.getDefaultSecret(),
65
+ authenticationHandler: this.handleAuthentication.bind(this),
66
+ accountingHandler: this.handleAccounting.bind(this),
67
+ });
68
+ // Configure per-client secrets
69
+ for (const [ip, secret] of this.clientSecrets) {
70
+ this.radiusServer.setClientSecret(ip, secret);
71
+ }
72
+ // Start the server
73
+ await this.radiusServer.start();
74
+ this.running = true;
75
+ this.stats.startTime = Date.now();
76
+ logger.log('info', `RADIUS server started with ${this.config.clients.length} configured clients`);
77
+ }
78
+ /**
79
+ * Stop the RADIUS server
80
+ */
81
+ async stop() {
82
+ if (!this.running) {
83
+ return;
84
+ }
85
+ logger.log('info', 'Stopping RADIUS server...');
86
+ if (this.radiusServer) {
87
+ await this.radiusServer.stop();
88
+ this.radiusServer = undefined;
89
+ }
90
+ this.running = false;
91
+ logger.log('info', 'RADIUS server stopped');
92
+ }
93
+ /**
94
+ * Handle authentication request
95
+ */
96
+ async handleAuthentication(request) {
97
+ this.stats.authRequests++;
98
+ const authData = {
99
+ username: request.attributes?.UserName || '',
100
+ password: request.attributes?.UserPassword,
101
+ nasIpAddress: request.attributes?.NasIpAddress || request.source?.address || '',
102
+ nasPort: request.attributes?.NasPort,
103
+ nasPortType: request.attributes?.NasPortType,
104
+ nasIdentifier: request.attributes?.NasIdentifier,
105
+ calledStationId: request.attributes?.CalledStationId,
106
+ callingStationId: request.attributes?.CallingStationId,
107
+ serviceType: request.attributes?.ServiceType,
108
+ };
109
+ logger.log('debug', `RADIUS Auth Request: user=${authData.username}, NAS=${authData.nasIpAddress}`);
110
+ // Perform MAC Authentication Bypass (MAB)
111
+ // In MAB, the username is typically the MAC address
112
+ const result = await this.performMabAuthentication(authData);
113
+ if (result.success) {
114
+ this.stats.authAccepts++;
115
+ logger.log('info', `RADIUS Auth Accept: user=${authData.username}, VLAN=${result.vlanId}`);
116
+ // Build response with VLAN attributes
117
+ const response = {
118
+ code: plugins.smartradius.ERadiusCode.AccessAccept,
119
+ replyMessage: result.replyMessage,
120
+ };
121
+ // Add VLAN attributes if assigned
122
+ if (result.vlanId !== undefined) {
123
+ response.tunnelType = 13; // VLAN
124
+ response.tunnelMediumType = 6; // IEEE 802
125
+ response.tunnelPrivateGroupId = String(result.vlanId);
126
+ }
127
+ // Add session timeout if specified
128
+ if (result.sessionTimeout) {
129
+ response.sessionTimeout = result.sessionTimeout;
130
+ }
131
+ // Add idle timeout if specified
132
+ if (result.idleTimeout) {
133
+ response.idleTimeout = result.idleTimeout;
134
+ }
135
+ // Add framed IP if specified
136
+ if (result.framedIpAddress) {
137
+ response.framedIpAddress = result.framedIpAddress;
138
+ }
139
+ return response;
140
+ }
141
+ else {
142
+ this.stats.authRejects++;
143
+ logger.log('warn', `RADIUS Auth Reject: user=${authData.username}, reason=${result.rejectReason}`);
144
+ return {
145
+ code: plugins.smartradius.ERadiusCode.AccessReject,
146
+ replyMessage: result.rejectReason || 'Access Denied',
147
+ };
148
+ }
149
+ }
150
+ /**
151
+ * Handle accounting request
152
+ */
153
+ async handleAccounting(request) {
154
+ this.stats.accountingRequests++;
155
+ if (!this.config.accounting?.enabled) {
156
+ // Still respond even if not tracking
157
+ return { code: plugins.smartradius.ERadiusCode.AccountingResponse };
158
+ }
159
+ const statusType = request.attributes?.AcctStatusType;
160
+ const sessionId = request.attributes?.AcctSessionId || '';
161
+ const accountingData = {
162
+ sessionId,
163
+ username: request.attributes?.UserName || '',
164
+ macAddress: request.attributes?.CallingStationId,
165
+ nasIpAddress: request.attributes?.NasIpAddress || request.source?.address || '',
166
+ nasPort: request.attributes?.NasPort,
167
+ nasPortType: request.attributes?.NasPortType,
168
+ nasIdentifier: request.attributes?.NasIdentifier,
169
+ calledStationId: request.attributes?.CalledStationId,
170
+ callingStationId: request.attributes?.CallingStationId,
171
+ inputOctets: request.attributes?.AcctInputOctets,
172
+ outputOctets: request.attributes?.AcctOutputOctets,
173
+ inputPackets: request.attributes?.AcctInputPackets,
174
+ outputPackets: request.attributes?.AcctOutputPackets,
175
+ sessionTime: request.attributes?.AcctSessionTime,
176
+ terminateCause: request.attributes?.AcctTerminateCause,
177
+ serviceType: request.attributes?.ServiceType,
178
+ };
179
+ try {
180
+ switch (statusType) {
181
+ case plugins.smartradius.EAcctStatusType.Start:
182
+ logger.log('debug', `RADIUS Acct Start: session=${sessionId}, user=${accountingData.username}`);
183
+ await this.accountingManager.handleAccountingStart(accountingData);
184
+ break;
185
+ case plugins.smartradius.EAcctStatusType.Stop:
186
+ logger.log('debug', `RADIUS Acct Stop: session=${sessionId}`);
187
+ await this.accountingManager.handleAccountingStop(accountingData);
188
+ break;
189
+ case plugins.smartradius.EAcctStatusType.InterimUpdate:
190
+ logger.log('debug', `RADIUS Acct Interim: session=${sessionId}`);
191
+ await this.accountingManager.handleAccountingUpdate(accountingData);
192
+ break;
193
+ default:
194
+ logger.log('debug', `RADIUS Acct Unknown status type: ${statusType}`);
195
+ }
196
+ }
197
+ catch (error) {
198
+ logger.log('error', `RADIUS accounting error: ${error.message}`);
199
+ }
200
+ return { code: plugins.smartradius.ERadiusCode.AccountingResponse };
201
+ }
202
+ /**
203
+ * Perform MAC Authentication Bypass
204
+ */
205
+ async performMabAuthentication(data) {
206
+ // Extract MAC address from username or CallingStationId
207
+ const macAddress = this.extractMacAddress(data);
208
+ if (!macAddress) {
209
+ return {
210
+ success: false,
211
+ rejectReason: 'No MAC address found',
212
+ };
213
+ }
214
+ // Look up VLAN assignment
215
+ const vlanResult = this.vlanManager.assignVlan(macAddress);
216
+ if (!vlanResult.assigned) {
217
+ return {
218
+ success: false,
219
+ rejectReason: 'Unknown MAC address',
220
+ };
221
+ }
222
+ // Build successful result
223
+ const result = {
224
+ success: true,
225
+ vlanId: vlanResult.vlan,
226
+ replyMessage: vlanResult.isDefault
227
+ ? `Assigned to default VLAN ${vlanResult.vlan}`
228
+ : `Assigned to VLAN ${vlanResult.vlan}`,
229
+ };
230
+ // Apply any additional settings from the matched rule
231
+ if (vlanResult.matchedRule) {
232
+ // Future: Add session timeout, idle timeout, etc. from rule
233
+ }
234
+ return result;
235
+ }
236
+ /**
237
+ * Extract MAC address from authentication data
238
+ */
239
+ extractMacAddress(data) {
240
+ // Try CallingStationId first (most common for MAB)
241
+ if (data.callingStationId) {
242
+ return this.normalizeMac(data.callingStationId);
243
+ }
244
+ // Try username (often MAC address in MAB)
245
+ if (data.username && this.looksLikeMac(data.username)) {
246
+ return this.normalizeMac(data.username);
247
+ }
248
+ return null;
249
+ }
250
+ /**
251
+ * Check if a string looks like a MAC address
252
+ */
253
+ looksLikeMac(value) {
254
+ // Remove common separators and check length
255
+ const cleaned = value.replace(/[-:. ]/g, '');
256
+ return /^[0-9a-fA-F]{12}$/.test(cleaned);
257
+ }
258
+ /**
259
+ * Normalize MAC address format
260
+ */
261
+ normalizeMac(mac) {
262
+ return this.vlanManager.normalizeMac(mac);
263
+ }
264
+ /**
265
+ * Build client secrets map from configuration
266
+ */
267
+ buildClientSecretsMap() {
268
+ this.clientSecrets.clear();
269
+ for (const client of this.config.clients) {
270
+ if (!client.enabled) {
271
+ continue;
272
+ }
273
+ // Handle CIDR ranges
274
+ if (client.ipRange.includes('/')) {
275
+ // For CIDR ranges, we'll use the network address as key
276
+ // In practice, smartradius may handle this differently
277
+ const [network] = client.ipRange.split('/');
278
+ this.clientSecrets.set(network, client.secret);
279
+ }
280
+ else {
281
+ this.clientSecrets.set(client.ipRange, client.secret);
282
+ }
283
+ }
284
+ }
285
+ /**
286
+ * Get default secret for unknown clients
287
+ */
288
+ getDefaultSecret() {
289
+ // Use first enabled client's secret as default, or a random one
290
+ for (const client of this.config.clients) {
291
+ if (client.enabled) {
292
+ return client.secret;
293
+ }
294
+ }
295
+ return plugins.crypto.randomBytes(16).toString('hex');
296
+ }
297
+ /**
298
+ * Add a RADIUS client
299
+ */
300
+ async addClient(client) {
301
+ // Check if client already exists
302
+ const existingIndex = this.config.clients.findIndex(c => c.name === client.name);
303
+ if (existingIndex >= 0) {
304
+ this.config.clients[existingIndex] = client;
305
+ }
306
+ else {
307
+ this.config.clients.push(client);
308
+ }
309
+ // Update client secrets if running
310
+ if (this.running && this.radiusServer && client.enabled) {
311
+ if (client.ipRange.includes('/')) {
312
+ const [network] = client.ipRange.split('/');
313
+ this.radiusServer.setClientSecret(network, client.secret);
314
+ this.clientSecrets.set(network, client.secret);
315
+ }
316
+ else {
317
+ this.radiusServer.setClientSecret(client.ipRange, client.secret);
318
+ this.clientSecrets.set(client.ipRange, client.secret);
319
+ }
320
+ }
321
+ logger.log('info', `RADIUS client ${client.enabled ? 'added' : 'disabled'}: ${client.name} (${client.ipRange})`);
322
+ }
323
+ /**
324
+ * Remove a RADIUS client
325
+ */
326
+ removeClient(name) {
327
+ const index = this.config.clients.findIndex(c => c.name === name);
328
+ if (index >= 0) {
329
+ const client = this.config.clients[index];
330
+ this.config.clients.splice(index, 1);
331
+ // Remove from secrets map
332
+ if (client.ipRange.includes('/')) {
333
+ const [network] = client.ipRange.split('/');
334
+ this.clientSecrets.delete(network);
335
+ }
336
+ else {
337
+ this.clientSecrets.delete(client.ipRange);
338
+ }
339
+ logger.log('info', `RADIUS client removed: ${name}`);
340
+ return true;
341
+ }
342
+ return false;
343
+ }
344
+ /**
345
+ * Get configured clients
346
+ */
347
+ getClients() {
348
+ return [...this.config.clients];
349
+ }
350
+ /**
351
+ * Get VLAN manager for direct access to VLAN operations
352
+ */
353
+ getVlanManager() {
354
+ return this.vlanManager;
355
+ }
356
+ /**
357
+ * Get accounting manager for direct access to accounting operations
358
+ */
359
+ getAccountingManager() {
360
+ return this.accountingManager;
361
+ }
362
+ /**
363
+ * Get server statistics
364
+ */
365
+ getStats() {
366
+ return {
367
+ running: this.running,
368
+ uptime: this.running ? Date.now() - this.stats.startTime : 0,
369
+ authRequests: this.stats.authRequests,
370
+ authAccepts: this.stats.authAccepts,
371
+ authRejects: this.stats.authRejects,
372
+ accountingRequests: this.stats.accountingRequests,
373
+ activeSessions: this.accountingManager.getStats().activeSessions,
374
+ vlanMappings: this.vlanManager.getStats().totalMappings,
375
+ clients: this.config.clients.filter(c => c.enabled).length,
376
+ };
377
+ }
378
+ /**
379
+ * Check if server is running
380
+ */
381
+ isRunning() {
382
+ return this.running;
383
+ }
384
+ }
385
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5yYWRpdXMuc2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvcmFkaXVzL2NsYXNzZXMucmFkaXVzLnNlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRXRDLE9BQU8sRUFBRSxXQUFXLEVBQWlELE1BQU0sMkJBQTJCLENBQUM7QUFDdkcsT0FBTyxFQUFFLGlCQUFpQixFQUEwRCxNQUFNLGlDQUFpQyxDQUFDO0FBOEU1SDs7Ozs7O0dBTUc7QUFDSCxNQUFNLE9BQU8sWUFBWTtJQUNmLFlBQVksQ0FBb0M7SUFDaEQsV0FBVyxDQUFjO0lBQ3pCLGlCQUFpQixDQUFvQjtJQUNyQyxNQUFNLENBQXNCO0lBQzVCLGNBQWMsQ0FBa0I7SUFDaEMsYUFBYSxHQUF3QixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQy9DLE9BQU8sR0FBWSxLQUFLLENBQUM7SUFFakMsYUFBYTtJQUNMLEtBQUssR0FBRztRQUNkLFlBQVksRUFBRSxDQUFDO1FBQ2YsV0FBVyxFQUFFLENBQUM7UUFDZCxXQUFXLEVBQUUsQ0FBQztRQUNkLGtCQUFrQixFQUFFLENBQUM7UUFDckIsU0FBUyxFQUFFLENBQUM7S0FDYixDQUFDO0lBRUYsWUFBWSxNQUEyQixFQUFFLGNBQStCO1FBQ3RFLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVEsSUFBSSxJQUFJO1lBQ2pDLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxJQUFJLElBQUk7WUFDakMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXLElBQUksU0FBUztZQUM1QyxHQUFHLE1BQU07U0FDVixDQUFDO1FBQ0YsSUFBSSxDQUFDLGNBQWMsR0FBRyxjQUFjLENBQUM7UUFFckMsMEJBQTBCO1FBQzFCLElBQUksQ0FBQyxX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