@serve.zone/dcrouter 11.12.3 → 11.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_serve/bundle.js +705 -548
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +30 -0
- package/dist_ts/classes.dcrouter.js +104 -5
- package/dist_ts/config/classes.route-config-manager.d.ts +2 -1
- package/dist_ts/config/classes.route-config-manager.js +21 -5
- package/dist_ts/opsserver/classes.opsserver.d.ts +1 -0
- package/dist_ts/opsserver/classes.opsserver.js +3 -1
- package/dist_ts/opsserver/handlers/index.d.ts +1 -0
- package/dist_ts/opsserver/handlers/index.js +2 -1
- package/dist_ts/opsserver/handlers/vpn.handler.d.ts +6 -0
- package/dist_ts/opsserver/handlers/vpn.handler.js +199 -0
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/vpn/classes.vpn-manager.d.ts +113 -0
- package/dist_ts/vpn/classes.vpn-manager.js +297 -0
- package/dist_ts/vpn/index.d.ts +1 -0
- package/dist_ts/vpn/index.js +2 -0
- package/dist_ts_interfaces/data/index.d.ts +1 -0
- package/dist_ts_interfaces/data/index.js +2 -1
- package/dist_ts_interfaces/data/remoteingress.d.ts +10 -1
- package/dist_ts_interfaces/data/vpn.d.ts +43 -0
- package/dist_ts_interfaces/data/vpn.js +2 -0
- package/dist_ts_interfaces/requests/index.d.ts +1 -0
- package/dist_ts_interfaces/requests/index.js +2 -1
- package/dist_ts_interfaces/requests/vpn.d.ts +135 -0
- package/dist_ts_interfaces/requests/vpn.js +3 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +22 -0
- package/dist_ts_web/appstate.js +111 -1
- package/dist_ts_web/elements/index.d.ts +1 -0
- package/dist_ts_web/elements/index.js +2 -1
- package/dist_ts_web/elements/ops-dashboard.js +7 -1
- package/dist_ts_web/elements/ops-view-vpn.d.ts +14 -0
- package/dist_ts_web/elements/ops-view-vpn.js +369 -0
- package/package.json +4 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +137 -3
- package/ts/config/classes.route-config-manager.ts +20 -3
- package/ts/opsserver/classes.opsserver.ts +2 -0
- package/ts/opsserver/handlers/index.ts +2 -1
- package/ts/opsserver/handlers/vpn.handler.ts +257 -0
- package/ts/plugins.ts +2 -1
- package/ts/vpn/classes.vpn-manager.ts +378 -0
- package/ts/vpn/index.ts +1 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +164 -0
- package/ts_web/elements/index.ts +1 -0
- package/ts_web/elements/ops-dashboard.ts +6 -0
- package/ts_web/elements/ops-view-vpn.ts +330 -0
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
IMergedRoute,
|
|
8
8
|
IRouteWarning,
|
|
9
9
|
} from '../../ts_interfaces/data/route-management.js';
|
|
10
|
+
import type { IDcRouterRouteConfig } from '../../ts_interfaces/data/remoteingress.js';
|
|
10
11
|
import { type IHttp3Config, augmentRouteWithHttp3 } from '../http3/index.js';
|
|
11
12
|
|
|
12
13
|
const ROUTES_PREFIX = '/config-api/routes/';
|
|
@@ -22,6 +23,7 @@ export class RouteConfigManager {
|
|
|
22
23
|
private getHardcodedRoutes: () => plugins.smartproxy.IRouteConfig[],
|
|
23
24
|
private getSmartProxy: () => plugins.smartproxy.SmartProxy | undefined,
|
|
24
25
|
private getHttp3Config?: () => IHttp3Config | undefined,
|
|
26
|
+
private getVpnSubnet?: () => string | undefined,
|
|
25
27
|
) {}
|
|
26
28
|
|
|
27
29
|
/**
|
|
@@ -262,13 +264,28 @@ export class RouteConfigManager {
|
|
|
262
264
|
|
|
263
265
|
// Add enabled programmatic routes (with HTTP/3 augmentation if enabled)
|
|
264
266
|
const http3Config = this.getHttp3Config?.();
|
|
267
|
+
const vpnSubnet = this.getVpnSubnet?.();
|
|
265
268
|
for (const stored of this.storedRoutes.values()) {
|
|
266
269
|
if (stored.enabled) {
|
|
270
|
+
let route = stored.route;
|
|
267
271
|
if (http3Config && http3Config.enabled !== false) {
|
|
268
|
-
|
|
269
|
-
} else {
|
|
270
|
-
enabledRoutes.push(stored.route);
|
|
272
|
+
route = augmentRouteWithHttp3(route, { enabled: true, ...http3Config });
|
|
271
273
|
}
|
|
274
|
+
// Inject VPN security for programmatic routes with vpn.required
|
|
275
|
+
if (vpnSubnet) {
|
|
276
|
+
const dcRoute = route as IDcRouterRouteConfig;
|
|
277
|
+
if (dcRoute.vpn?.required) {
|
|
278
|
+
const existing = route.security?.ipAllowList || [];
|
|
279
|
+
route = {
|
|
280
|
+
...route,
|
|
281
|
+
security: {
|
|
282
|
+
...route.security,
|
|
283
|
+
ipAllowList: [...existing, vpnSubnet],
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
enabledRoutes.push(route);
|
|
272
289
|
}
|
|
273
290
|
}
|
|
274
291
|
|
|
@@ -28,6 +28,7 @@ export class OpsServer {
|
|
|
28
28
|
private remoteIngressHandler!: handlers.RemoteIngressHandler;
|
|
29
29
|
private routeManagementHandler!: handlers.RouteManagementHandler;
|
|
30
30
|
private apiTokenHandler!: handlers.ApiTokenHandler;
|
|
31
|
+
private vpnHandler!: handlers.VpnHandler;
|
|
31
32
|
|
|
32
33
|
constructor(dcRouterRefArg: DcRouter) {
|
|
33
34
|
this.dcRouterRef = dcRouterRefArg;
|
|
@@ -86,6 +87,7 @@ export class OpsServer {
|
|
|
86
87
|
this.remoteIngressHandler = new handlers.RemoteIngressHandler(this);
|
|
87
88
|
this.routeManagementHandler = new handlers.RouteManagementHandler(this);
|
|
88
89
|
this.apiTokenHandler = new handlers.ApiTokenHandler(this);
|
|
90
|
+
this.vpnHandler = new handlers.VpnHandler(this);
|
|
89
91
|
|
|
90
92
|
console.log('✅ OpsServer TypedRequest handlers initialized');
|
|
91
93
|
}
|
|
@@ -8,4 +8,5 @@ export * from './email-ops.handler.js';
|
|
|
8
8
|
export * from './certificate.handler.js';
|
|
9
9
|
export * from './remoteingress.handler.js';
|
|
10
10
|
export * from './route-management.handler.js';
|
|
11
|
-
export * from './api-token.handler.js';
|
|
11
|
+
export * from './api-token.handler.js';
|
|
12
|
+
export * from './vpn.handler.js';
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
|
+
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
4
|
+
|
|
5
|
+
export class VpnHandler {
|
|
6
|
+
constructor(private opsServerRef: OpsServer) {
|
|
7
|
+
this.registerHandlers();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
private registerHandlers(): void {
|
|
11
|
+
const viewRouter = this.opsServerRef.viewRouter;
|
|
12
|
+
const adminRouter = this.opsServerRef.adminRouter;
|
|
13
|
+
|
|
14
|
+
// ---- Read endpoints (viewRouter — valid identity required via middleware) ----
|
|
15
|
+
|
|
16
|
+
// Get all registered VPN clients
|
|
17
|
+
viewRouter.addTypedHandler(
|
|
18
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnClients>(
|
|
19
|
+
'getVpnClients',
|
|
20
|
+
async (dataArg, toolsArg) => {
|
|
21
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
22
|
+
if (!manager) {
|
|
23
|
+
return { clients: [] };
|
|
24
|
+
}
|
|
25
|
+
const clients = manager.listClients().map((c) => ({
|
|
26
|
+
clientId: c.clientId,
|
|
27
|
+
enabled: c.enabled,
|
|
28
|
+
tags: c.tags,
|
|
29
|
+
description: c.description,
|
|
30
|
+
assignedIp: c.assignedIp,
|
|
31
|
+
createdAt: c.createdAt,
|
|
32
|
+
updatedAt: c.updatedAt,
|
|
33
|
+
expiresAt: c.expiresAt,
|
|
34
|
+
}));
|
|
35
|
+
return { clients };
|
|
36
|
+
},
|
|
37
|
+
),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Get VPN server status
|
|
41
|
+
viewRouter.addTypedHandler(
|
|
42
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnStatus>(
|
|
43
|
+
'getVpnStatus',
|
|
44
|
+
async (dataArg, toolsArg) => {
|
|
45
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
46
|
+
const vpnConfig = this.opsServerRef.dcRouterRef.options.vpnConfig;
|
|
47
|
+
if (!manager) {
|
|
48
|
+
return {
|
|
49
|
+
status: {
|
|
50
|
+
running: false,
|
|
51
|
+
forwardingMode: 'socket' as const,
|
|
52
|
+
subnet: vpnConfig?.subnet || '10.8.0.0/24',
|
|
53
|
+
wgListenPort: vpnConfig?.wgListenPort ?? 51820,
|
|
54
|
+
serverPublicKeys: null,
|
|
55
|
+
registeredClients: 0,
|
|
56
|
+
connectedClients: 0,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const connected = await manager.getConnectedClients();
|
|
62
|
+
return {
|
|
63
|
+
status: {
|
|
64
|
+
running: manager.running,
|
|
65
|
+
forwardingMode: manager.forwardingMode,
|
|
66
|
+
subnet: manager.getSubnet(),
|
|
67
|
+
wgListenPort: vpnConfig?.wgListenPort ?? 51820,
|
|
68
|
+
serverPublicKeys: manager.getServerPublicKeys(),
|
|
69
|
+
registeredClients: manager.listClients().length,
|
|
70
|
+
connectedClients: connected.length,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// ---- Write endpoints (adminRouter — admin identity required via middleware) ----
|
|
78
|
+
|
|
79
|
+
// Create a new VPN client
|
|
80
|
+
adminRouter.addTypedHandler(
|
|
81
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateVpnClient>(
|
|
82
|
+
'createVpnClient',
|
|
83
|
+
async (dataArg, toolsArg) => {
|
|
84
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
85
|
+
if (!manager) {
|
|
86
|
+
return { success: false, message: 'VPN not configured' };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const bundle = await manager.createClient({
|
|
91
|
+
clientId: dataArg.clientId,
|
|
92
|
+
tags: dataArg.tags,
|
|
93
|
+
description: dataArg.description,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
success: true,
|
|
98
|
+
client: {
|
|
99
|
+
clientId: bundle.entry.clientId,
|
|
100
|
+
enabled: bundle.entry.enabled ?? true,
|
|
101
|
+
tags: bundle.entry.tags,
|
|
102
|
+
description: bundle.entry.description,
|
|
103
|
+
assignedIp: bundle.entry.assignedIp,
|
|
104
|
+
createdAt: Date.now(),
|
|
105
|
+
updatedAt: Date.now(),
|
|
106
|
+
expiresAt: bundle.entry.expiresAt,
|
|
107
|
+
},
|
|
108
|
+
wireguardConfig: bundle.wireguardConfig,
|
|
109
|
+
};
|
|
110
|
+
} catch (err: unknown) {
|
|
111
|
+
return { success: false, message: (err as Error).message };
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Delete a VPN client
|
|
118
|
+
adminRouter.addTypedHandler(
|
|
119
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteVpnClient>(
|
|
120
|
+
'deleteVpnClient',
|
|
121
|
+
async (dataArg, toolsArg) => {
|
|
122
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
123
|
+
if (!manager) {
|
|
124
|
+
return { success: false, message: 'VPN not configured' };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await manager.removeClient(dataArg.clientId);
|
|
129
|
+
return { success: true };
|
|
130
|
+
} catch (err: unknown) {
|
|
131
|
+
return { success: false, message: (err as Error).message };
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Enable a VPN client
|
|
138
|
+
adminRouter.addTypedHandler(
|
|
139
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_EnableVpnClient>(
|
|
140
|
+
'enableVpnClient',
|
|
141
|
+
async (dataArg, toolsArg) => {
|
|
142
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
143
|
+
if (!manager) {
|
|
144
|
+
return { success: false, message: 'VPN not configured' };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
await manager.enableClient(dataArg.clientId);
|
|
149
|
+
return { success: true };
|
|
150
|
+
} catch (err: unknown) {
|
|
151
|
+
return { success: false, message: (err as Error).message };
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
),
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Disable a VPN client
|
|
158
|
+
adminRouter.addTypedHandler(
|
|
159
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DisableVpnClient>(
|
|
160
|
+
'disableVpnClient',
|
|
161
|
+
async (dataArg, toolsArg) => {
|
|
162
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
163
|
+
if (!manager) {
|
|
164
|
+
return { success: false, message: 'VPN not configured' };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
await manager.disableClient(dataArg.clientId);
|
|
169
|
+
return { success: true };
|
|
170
|
+
} catch (err: unknown) {
|
|
171
|
+
return { success: false, message: (err as Error).message };
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
),
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
// Rotate a VPN client's keys
|
|
178
|
+
adminRouter.addTypedHandler(
|
|
179
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RotateVpnClientKey>(
|
|
180
|
+
'rotateVpnClientKey',
|
|
181
|
+
async (dataArg, toolsArg) => {
|
|
182
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
183
|
+
if (!manager) {
|
|
184
|
+
return { success: false, message: 'VPN not configured' };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const bundle = await manager.rotateClientKey(dataArg.clientId);
|
|
189
|
+
return {
|
|
190
|
+
success: true,
|
|
191
|
+
wireguardConfig: bundle.wireguardConfig,
|
|
192
|
+
};
|
|
193
|
+
} catch (err: unknown) {
|
|
194
|
+
return { success: false, message: (err as Error).message };
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
// Export a VPN client config
|
|
201
|
+
adminRouter.addTypedHandler(
|
|
202
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ExportVpnClientConfig>(
|
|
203
|
+
'exportVpnClientConfig',
|
|
204
|
+
async (dataArg, toolsArg) => {
|
|
205
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
206
|
+
if (!manager) {
|
|
207
|
+
return { success: false, message: 'VPN not configured' };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const config = await manager.exportClientConfig(dataArg.clientId, dataArg.format);
|
|
212
|
+
return { success: true, config };
|
|
213
|
+
} catch (err: unknown) {
|
|
214
|
+
return { success: false, message: (err as Error).message };
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
),
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Get telemetry for a specific VPN client
|
|
221
|
+
viewRouter.addTypedHandler(
|
|
222
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnClientTelemetry>(
|
|
223
|
+
'getVpnClientTelemetry',
|
|
224
|
+
async (dataArg, toolsArg) => {
|
|
225
|
+
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
226
|
+
if (!manager) {
|
|
227
|
+
return { success: false, message: 'VPN not configured' };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
const telemetry = await manager.getClientTelemetry(dataArg.clientId);
|
|
232
|
+
if (!telemetry) {
|
|
233
|
+
return { success: false, message: 'Client not found or not connected' };
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
success: true,
|
|
237
|
+
telemetry: {
|
|
238
|
+
clientId: telemetry.clientId,
|
|
239
|
+
assignedIp: telemetry.assignedIp,
|
|
240
|
+
bytesSent: telemetry.bytesSent,
|
|
241
|
+
bytesReceived: telemetry.bytesReceived,
|
|
242
|
+
packetsDropped: telemetry.packetsDropped,
|
|
243
|
+
bytesDropped: telemetry.bytesDropped,
|
|
244
|
+
lastKeepaliveAt: telemetry.lastKeepaliveAt,
|
|
245
|
+
keepalivesReceived: telemetry.keepalivesReceived,
|
|
246
|
+
rateLimitBytesPerSec: telemetry.rateLimitBytesPerSec,
|
|
247
|
+
burstBytes: telemetry.burstBytes,
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
} catch (err: unknown) {
|
|
251
|
+
return { success: false, message: (err as Error).message };
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
),
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
}
|
package/ts/plugins.ts
CHANGED
|
@@ -58,13 +58,14 @@ import * as smartnetwork from '@push.rocks/smartnetwork';
|
|
|
58
58
|
import * as smartpath from '@push.rocks/smartpath';
|
|
59
59
|
import * as smartproxy from '@push.rocks/smartproxy';
|
|
60
60
|
import * as smartpromise from '@push.rocks/smartpromise';
|
|
61
|
+
import * as smartvpn from '@push.rocks/smartvpn';
|
|
61
62
|
import * as smartradius from '@push.rocks/smartradius';
|
|
62
63
|
import * as smartrequest from '@push.rocks/smartrequest';
|
|
63
64
|
import * as smartrx from '@push.rocks/smartrx';
|
|
64
65
|
import * as smartunique from '@push.rocks/smartunique';
|
|
65
66
|
import * as taskbuffer from '@push.rocks/taskbuffer';
|
|
66
67
|
|
|
67
|
-
export { projectinfo, qenv, smartacme, smartdata, smartdns, smartfs, smartguard, smartjwt, smartlog, smartmetrics, smartdb, smartmta, smartnetwork, smartpath, smartproxy, smartpromise, smartradius, smartrequest, smartrx, smartunique, taskbuffer };
|
|
68
|
+
export { projectinfo, qenv, smartacme, smartdata, smartdns, smartfs, smartguard, smartjwt, smartlog, smartmetrics, smartdb, smartmta, smartnetwork, smartpath, smartproxy, smartpromise, smartradius, smartrequest, smartrx, smartunique, smartvpn, taskbuffer };
|
|
68
69
|
|
|
69
70
|
// Define SmartLog types for use in error handling
|
|
70
71
|
export type TLogLevel = 'error' | 'warn' | 'info' | 'success' | 'debug';
|