@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
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
import { DeesElement, html, customElement, css, state, cssManager, } from '@design.estate/dees-element';
|
|
36
|
+
import * as appstate from '../appstate.js';
|
|
37
|
+
import * as interfaces from '../../dist_ts_interfaces/index.js';
|
|
38
|
+
import { viewHostCss } from './shared/css.js';
|
|
39
|
+
import {} from '@design.estate/dees-catalog';
|
|
40
|
+
let OpsViewVpn = (() => {
|
|
41
|
+
let _classDecorators = [customElement('ops-view-vpn')];
|
|
42
|
+
let _classDescriptor;
|
|
43
|
+
let _classExtraInitializers = [];
|
|
44
|
+
let _classThis;
|
|
45
|
+
let _classSuper = DeesElement;
|
|
46
|
+
let _vpnState_decorators;
|
|
47
|
+
let _vpnState_initializers = [];
|
|
48
|
+
let _vpnState_extraInitializers = [];
|
|
49
|
+
var OpsViewVpn = class extends _classSuper {
|
|
50
|
+
static { _classThis = this; }
|
|
51
|
+
static {
|
|
52
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
53
|
+
_vpnState_decorators = [state()];
|
|
54
|
+
__esDecorate(this, null, _vpnState_decorators, { kind: "accessor", name: "vpnState", static: false, private: false, access: { has: obj => "vpnState" in obj, get: obj => obj.vpnState, set: (obj, value) => { obj.vpnState = value; } }, metadata: _metadata }, _vpnState_initializers, _vpnState_extraInitializers);
|
|
55
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
56
|
+
OpsViewVpn = _classThis = _classDescriptor.value;
|
|
57
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
58
|
+
}
|
|
59
|
+
#vpnState_accessor_storage = __runInitializers(this, _vpnState_initializers, appstate.vpnStatePart.getState());
|
|
60
|
+
get vpnState() { return this.#vpnState_accessor_storage; }
|
|
61
|
+
set vpnState(value) { this.#vpnState_accessor_storage = value; }
|
|
62
|
+
constructor() {
|
|
63
|
+
super();
|
|
64
|
+
__runInitializers(this, _vpnState_extraInitializers);
|
|
65
|
+
const sub = appstate.vpnStatePart.select().subscribe((newState) => {
|
|
66
|
+
this.vpnState = newState;
|
|
67
|
+
});
|
|
68
|
+
this.rxSubscriptions.push(sub);
|
|
69
|
+
}
|
|
70
|
+
async connectedCallback() {
|
|
71
|
+
await super.connectedCallback();
|
|
72
|
+
await appstate.vpnStatePart.dispatchAction(appstate.fetchVpnAction, null);
|
|
73
|
+
}
|
|
74
|
+
static styles = [
|
|
75
|
+
cssManager.defaultStyles,
|
|
76
|
+
viewHostCss,
|
|
77
|
+
css `
|
|
78
|
+
.vpnContainer {
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
gap: 24px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.statusBadge {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
padding: 3px 10px;
|
|
88
|
+
border-radius: 12px;
|
|
89
|
+
font-size: 12px;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
letter-spacing: 0.02em;
|
|
92
|
+
text-transform: uppercase;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.statusBadge.enabled {
|
|
96
|
+
background: ${cssManager.bdTheme('#dcfce7', '#14532d')};
|
|
97
|
+
color: ${cssManager.bdTheme('#166534', '#4ade80')};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.statusBadge.disabled {
|
|
101
|
+
background: ${cssManager.bdTheme('#fef2f2', '#450a0a')};
|
|
102
|
+
color: ${cssManager.bdTheme('#991b1b', '#f87171')};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.configDialog {
|
|
106
|
+
padding: 16px;
|
|
107
|
+
background: ${cssManager.bdTheme('#fffbeb', '#1c1917')};
|
|
108
|
+
border: 1px solid ${cssManager.bdTheme('#fbbf24', '#92400e')};
|
|
109
|
+
border-radius: 8px;
|
|
110
|
+
margin-bottom: 16px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.configDialog pre {
|
|
114
|
+
display: block;
|
|
115
|
+
padding: 12px;
|
|
116
|
+
background: ${cssManager.bdTheme('#1f2937', '#111827')};
|
|
117
|
+
color: #10b981;
|
|
118
|
+
border-radius: 4px;
|
|
119
|
+
font-family: monospace;
|
|
120
|
+
font-size: 12px;
|
|
121
|
+
white-space: pre-wrap;
|
|
122
|
+
word-break: break-all;
|
|
123
|
+
margin: 8px 0;
|
|
124
|
+
user-select: all;
|
|
125
|
+
max-height: 300px;
|
|
126
|
+
overflow-y: auto;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.configDialog .warning {
|
|
130
|
+
font-size: 12px;
|
|
131
|
+
color: ${cssManager.bdTheme('#92400e', '#fbbf24')};
|
|
132
|
+
margin-top: 8px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.tagBadge {
|
|
136
|
+
display: inline-flex;
|
|
137
|
+
padding: 2px 8px;
|
|
138
|
+
border-radius: 4px;
|
|
139
|
+
font-size: 12px;
|
|
140
|
+
font-weight: 500;
|
|
141
|
+
background: ${cssManager.bdTheme('#eff6ff', '#172554')};
|
|
142
|
+
color: ${cssManager.bdTheme('#1e40af', '#60a5fa')};
|
|
143
|
+
margin-right: 4px;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.serverInfo {
|
|
147
|
+
display: grid;
|
|
148
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
149
|
+
gap: 12px;
|
|
150
|
+
padding: 16px;
|
|
151
|
+
background: ${cssManager.bdTheme('#f9fafb', '#111827')};
|
|
152
|
+
border-radius: 8px;
|
|
153
|
+
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#1f2937')};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.serverInfo .infoItem {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-direction: column;
|
|
159
|
+
gap: 4px;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.serverInfo .infoLabel {
|
|
163
|
+
font-size: 11px;
|
|
164
|
+
font-weight: 600;
|
|
165
|
+
text-transform: uppercase;
|
|
166
|
+
letter-spacing: 0.05em;
|
|
167
|
+
color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.serverInfo .infoValue {
|
|
171
|
+
font-size: 14px;
|
|
172
|
+
font-family: monospace;
|
|
173
|
+
color: ${cssManager.bdTheme('#111827', '#f9fafb')};
|
|
174
|
+
}
|
|
175
|
+
`,
|
|
176
|
+
];
|
|
177
|
+
render() {
|
|
178
|
+
const status = this.vpnState.status;
|
|
179
|
+
const clients = this.vpnState.clients;
|
|
180
|
+
const connectedCount = status?.connectedClients ?? 0;
|
|
181
|
+
const totalClients = clients.length;
|
|
182
|
+
const enabledClients = clients.filter(c => c.enabled).length;
|
|
183
|
+
const statsTiles = [
|
|
184
|
+
{
|
|
185
|
+
id: 'totalClients',
|
|
186
|
+
title: 'Total Clients',
|
|
187
|
+
type: 'number',
|
|
188
|
+
value: totalClients,
|
|
189
|
+
icon: 'lucide:users',
|
|
190
|
+
description: 'Registered VPN clients',
|
|
191
|
+
color: '#3b82f6',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: 'connectedClients',
|
|
195
|
+
title: 'Connected',
|
|
196
|
+
type: 'number',
|
|
197
|
+
value: connectedCount,
|
|
198
|
+
icon: 'lucide:link',
|
|
199
|
+
description: 'Currently connected',
|
|
200
|
+
color: '#10b981',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
id: 'enabledClients',
|
|
204
|
+
title: 'Enabled',
|
|
205
|
+
type: 'number',
|
|
206
|
+
value: enabledClients,
|
|
207
|
+
icon: 'lucide:shieldCheck',
|
|
208
|
+
description: 'Active client registrations',
|
|
209
|
+
color: '#8b5cf6',
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: 'serverStatus',
|
|
213
|
+
title: 'Server',
|
|
214
|
+
type: 'text',
|
|
215
|
+
value: status?.running ? 'Running' : 'Stopped',
|
|
216
|
+
icon: 'lucide:server',
|
|
217
|
+
description: status?.running ? `${status.forwardingMode} mode` : 'VPN server not running',
|
|
218
|
+
color: status?.running ? '#10b981' : '#ef4444',
|
|
219
|
+
},
|
|
220
|
+
];
|
|
221
|
+
return html `
|
|
222
|
+
<ops-sectionheading>VPN</ops-sectionheading>
|
|
223
|
+
|
|
224
|
+
${this.vpnState.newClientConfig ? html `
|
|
225
|
+
<div class="configDialog">
|
|
226
|
+
<strong>Client created successfully!</strong>
|
|
227
|
+
<div class="warning">Copy the WireGuard config now. It contains private keys that won't be shown again.</div>
|
|
228
|
+
<pre>${this.vpnState.newClientConfig}</pre>
|
|
229
|
+
<dees-button
|
|
230
|
+
@click=${async () => {
|
|
231
|
+
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
|
|
232
|
+
await navigator.clipboard.writeText(this.vpnState.newClientConfig);
|
|
233
|
+
}
|
|
234
|
+
const { DeesToast } = await import('@design.estate/dees-catalog');
|
|
235
|
+
DeesToast.createAndShow({ message: 'Config copied to clipboard', type: 'success', duration: 3000 });
|
|
236
|
+
}}
|
|
237
|
+
>Copy to Clipboard</dees-button>
|
|
238
|
+
<dees-button
|
|
239
|
+
@click=${() => {
|
|
240
|
+
const blob = new Blob([this.vpnState.newClientConfig], { type: 'text/plain' });
|
|
241
|
+
const url = URL.createObjectURL(blob);
|
|
242
|
+
const a = document.createElement('a');
|
|
243
|
+
a.href = url;
|
|
244
|
+
a.download = 'wireguard.conf';
|
|
245
|
+
a.click();
|
|
246
|
+
URL.revokeObjectURL(url);
|
|
247
|
+
}}
|
|
248
|
+
>Download .conf</dees-button>
|
|
249
|
+
<dees-button
|
|
250
|
+
@click=${() => appstate.vpnStatePart.dispatchAction(appstate.clearNewClientConfigAction, null)}
|
|
251
|
+
>Dismiss</dees-button>
|
|
252
|
+
</div>
|
|
253
|
+
` : ''}
|
|
254
|
+
|
|
255
|
+
<dees-statsgrid .statsTiles=${statsTiles}></dees-statsgrid>
|
|
256
|
+
|
|
257
|
+
${status ? html `
|
|
258
|
+
<div class="serverInfo">
|
|
259
|
+
<div class="infoItem">
|
|
260
|
+
<span class="infoLabel">Subnet</span>
|
|
261
|
+
<span class="infoValue">${status.subnet}</span>
|
|
262
|
+
</div>
|
|
263
|
+
<div class="infoItem">
|
|
264
|
+
<span class="infoLabel">WireGuard Port</span>
|
|
265
|
+
<span class="infoValue">${status.wgListenPort}</span>
|
|
266
|
+
</div>
|
|
267
|
+
<div class="infoItem">
|
|
268
|
+
<span class="infoLabel">Forwarding Mode</span>
|
|
269
|
+
<span class="infoValue">${status.forwardingMode}</span>
|
|
270
|
+
</div>
|
|
271
|
+
${status.serverPublicKeys ? html `
|
|
272
|
+
<div class="infoItem">
|
|
273
|
+
<span class="infoLabel">WG Public Key</span>
|
|
274
|
+
<span class="infoValue" style="font-size: 11px; word-break: break-all;">${status.serverPublicKeys.wgPublicKey}</span>
|
|
275
|
+
</div>
|
|
276
|
+
` : ''}
|
|
277
|
+
</div>
|
|
278
|
+
` : ''}
|
|
279
|
+
|
|
280
|
+
<dees-table
|
|
281
|
+
.heading1=${'VPN Clients'}
|
|
282
|
+
.heading2=${'Manage WireGuard and SmartVPN client registrations'}
|
|
283
|
+
.data=${clients}
|
|
284
|
+
.displayFunction=${(client) => ({
|
|
285
|
+
'Client ID': client.clientId,
|
|
286
|
+
'Status': client.enabled
|
|
287
|
+
? html `<span class="statusBadge enabled">enabled</span>`
|
|
288
|
+
: html `<span class="statusBadge disabled">disabled</span>`,
|
|
289
|
+
'VPN IP': client.assignedIp || '-',
|
|
290
|
+
'Tags': client.tags?.length
|
|
291
|
+
? html `${client.tags.map(t => html `<span class="tagBadge">${t}</span>`)}`
|
|
292
|
+
: '-',
|
|
293
|
+
'Description': client.description || '-',
|
|
294
|
+
'Created': new Date(client.createdAt).toLocaleDateString(),
|
|
295
|
+
})}
|
|
296
|
+
.dataActions=${[
|
|
297
|
+
{
|
|
298
|
+
name: 'Toggle',
|
|
299
|
+
iconName: 'lucide:power',
|
|
300
|
+
action: async (client) => {
|
|
301
|
+
await appstate.vpnStatePart.dispatchAction(appstate.toggleVpnClientAction, {
|
|
302
|
+
clientId: client.clientId,
|
|
303
|
+
enabled: !client.enabled,
|
|
304
|
+
});
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
name: 'Delete',
|
|
309
|
+
iconName: 'lucide:trash2',
|
|
310
|
+
action: async (client) => {
|
|
311
|
+
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
312
|
+
DeesModal.createAndShow({
|
|
313
|
+
heading: 'Delete VPN Client',
|
|
314
|
+
content: html `<p>Are you sure you want to delete client "${client.clientId}"?</p>`,
|
|
315
|
+
menuOptions: [
|
|
316
|
+
{ name: 'Cancel', action: async (modal) => modal.destroy() },
|
|
317
|
+
{
|
|
318
|
+
name: 'Delete',
|
|
319
|
+
action: async (modal) => {
|
|
320
|
+
await appstate.vpnStatePart.dispatchAction(appstate.deleteVpnClientAction, client.clientId);
|
|
321
|
+
modal.destroy();
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
});
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
]}
|
|
329
|
+
.createNewItem=${async () => {
|
|
330
|
+
const { DeesModal, DeesForm, DeesInputText } = await import('@design.estate/dees-catalog');
|
|
331
|
+
DeesModal.createAndShow({
|
|
332
|
+
heading: 'Create VPN Client',
|
|
333
|
+
content: html `
|
|
334
|
+
<dees-form>
|
|
335
|
+
<dees-input-text id="clientId" .label=${'Client ID'} .key=${'clientId'} required></dees-input-text>
|
|
336
|
+
<dees-input-text id="description" .label=${'Description'} .key=${'description'}></dees-input-text>
|
|
337
|
+
<dees-input-text id="tags" .label=${'Tags (comma-separated)'} .key=${'tags'}></dees-input-text>
|
|
338
|
+
</dees-form>
|
|
339
|
+
`,
|
|
340
|
+
menuOptions: [
|
|
341
|
+
{ name: 'Cancel', action: async (modal) => modal.destroy() },
|
|
342
|
+
{
|
|
343
|
+
name: 'Create',
|
|
344
|
+
action: async (modal) => {
|
|
345
|
+
const form = modal.shadowRoot.querySelector('dees-form');
|
|
346
|
+
const data = await form.collectFormData();
|
|
347
|
+
const tags = data.tags ? data.tags.split(',').map((t) => t.trim()).filter(Boolean) : undefined;
|
|
348
|
+
await appstate.vpnStatePart.dispatchAction(appstate.createVpnClientAction, {
|
|
349
|
+
clientId: data.clientId,
|
|
350
|
+
description: data.description || undefined,
|
|
351
|
+
tags,
|
|
352
|
+
});
|
|
353
|
+
modal.destroy();
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
],
|
|
357
|
+
});
|
|
358
|
+
}}
|
|
359
|
+
></dees-table>
|
|
360
|
+
`;
|
|
361
|
+
}
|
|
362
|
+
static {
|
|
363
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
return OpsViewVpn = _classThis;
|
|
367
|
+
})();
|
|
368
|
+
export { OpsViewVpn };
|
|
369
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BzLXZpZXctdnBuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHNfd2ViL2VsZW1lbnRzL29wcy12aWV3LXZwbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsT0FBTyxFQUNMLFdBQVcsRUFDWCxJQUFJLEVBQ0osYUFBYSxFQUViLEdBQUcsRUFDSCxLQUFLLEVBQ0wsVUFBVSxHQUNYLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxLQUFLLFFBQVEsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEtBQUssVUFBVSxNQUFNLG1DQUFtQyxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM5QyxPQUFPLEVBQW1CLE1BQU0sNkJBQTZCLENBQUM7SUFTakQsVUFBVTs0QkFEdEIsYUFBYSxDQUFDLGNBQWMsQ0FBQzs7OztzQkFDRSxXQUFXOzs7OzBCQUFuQixTQUFRLFdBQVc7Ozs7b0NBQ3hDLEtBQUssRUFBRTtZQUNSLDZLQUFTLFFBQVEsNkJBQVIsUUFBUSwyRkFBeUQ7WUFGNUUsNktBb1RDOzs7O1FBbFRDLDZFQUF3QyxRQUFRLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRyxFQUFDO1FBQTFFLElBQVMsUUFBUSw4Q0FBeUQ7UUFBMUUsSUFBUyxRQUFRLG9EQUF5RDtRQUUxRTtZQUNFLEtBQUssRUFBRSxDQUFDOztZQUNSLE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7Z0JBQ2hFLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1lBQzNCLENBQUMsQ0FBQyxDQUFDO1lBQ0gsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDaEM7UUFFRCxLQUFLLENBQUMsaUJBQWlCO1lBQ3JCLE1BQU0sS0FBSyxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDaEMsTUFBTSxRQUFRLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsY0FBYyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzVFLENBQUM7UUFFTSxNQUFNLENBQUMsTUFBTSxHQUFHO1lBQ3JCLFVBQVUsQ0FBQyxhQUFhO1lBQ3hCLFdBQVc7WUFDWCxHQUFHLENBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7c0JBbUJlLFVBQVUsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQztpQkFDN0MsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDOzs7O3NCQUluQyxVQUFVLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUM7aUJBQzdDLFVBQVUsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQzs7Ozs7c0JBS25DLFVBQVUsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQzs0QkFDbEMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDOzs7Ozs7OztzQkFROUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7aUJBZTdDLFVBQVUsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQzs7Ozs7Ozs7OztzQkFVbkMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDO2lCQUM3QyxVQUFVLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUM7Ozs7Ozs7OztzQkFTbkMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDOzs0QkFFbEMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDOzs7Ozs7Ozs7Ozs7OztpQkFjbkQsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDOzs7Ozs7aUJBTXhDLFVBQVUsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQzs7S0FFcEQ7U0FDRixDQUFDO1FBRUYsTUFBTTtZQUNKLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO1lBQ3BDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO1lBQ3RDLE1BQU0sY0FBYyxHQUFHLE1BQU0sRUFBRSxnQkFBZ0IsSUFBSSxDQUFDLENBQUM7WUFDckQsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQztZQUNwQyxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FBQztZQUU3RCxNQUFNLFVBQVUsR0FBaUI7Z0JBQy9CO29CQUNFLEVBQUUsRUFBRSxjQUFjO29CQUNsQixLQUFLLEVBQUUsZUFBZTtvQkFDdEIsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsS0FBSyxFQUFFLFlBQVk7b0JBQ25CLElBQUksRUFBRSxjQUFjO29CQUNwQixXQUFXLEVBQUUsd0JBQXdCO29CQUNyQyxLQUFLLEVBQUUsU0FBUztpQkFDakI7Z0JBQ0Q7b0JBQ0UsRUFBRSxFQUFFLGtCQUFrQjtvQkFDdEIsS0FBSyxFQUFFLFdBQVc7b0JBQ2xCLElBQUksRUFBRSxRQUFRO29CQUNkLEtBQUssRUFBRSxjQUFjO29CQUNyQixJQUFJLEVBQUUsYUFBYTtvQkFDbkIsV0FBVyxFQUFFLHFCQUFxQjtvQkFDbEMsS0FBSyxFQUFFLFNBQVM7aUJBQ2pCO2dCQUNEO29CQUNFLEVBQUUsRUFBRSxnQkFBZ0I7b0JBQ3BCLEtBQUssRUFBRSxTQUFTO29CQUNoQixJQUFJLEVBQUUsUUFBUTtvQkFDZCxLQUFLLEVBQUUsY0FBYztvQkFDckIsSUFBSSxFQUFFLG9CQUFvQjtvQkFDMUIsV0FBVyxFQUFFLDZCQUE2QjtvQkFDMUMsS0FBSyxFQUFFLFNBQVM7aUJBQ2pCO2dCQUNEO29CQUNFLEVBQUUsRUFBRSxjQUFjO29CQUNsQixLQUFLLEVBQUUsUUFBUTtvQkFDZixJQUFJLEVBQUUsTUFBTTtvQkFDWixLQUFLLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTO29CQUM5QyxJQUFJLEVBQUUsZUFBZTtvQkFDckIsV0FBVyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLGNBQWMsT0FBTyxDQUFDLENBQUMsQ0FBQyx3QkFBd0I7b0JBQ3pGLEtBQUssRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFNBQVM7aUJBQy9DO2FBQ0YsQ0FBQztZQUVGLE9BQU8sSUFBSSxDQUFBOzs7UUFHUCxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFBOzs7O2lCQUkzQixJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWU7O3FCQUV6QixLQUFLLElBQUksRUFBRTtnQkFDbEIsSUFBSSxTQUFTLENBQUMsU0FBUyxJQUFJLE9BQU8sU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTLEtBQUssVUFBVSxFQUFFLENBQUM7b0JBQy9FLE1BQU0sU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxlQUFnQixDQUFDLENBQUM7Z0JBQ3RFLENBQUM7Z0JBQ0QsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLDZCQUE2QixDQUFDLENBQUM7Z0JBQ2xFLFNBQVMsQ0FBQyxhQUFhLENBQUMsRUFBRSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUN0RyxDQUFDOzs7cUJBR1EsR0FBRyxFQUFFO2dCQUNaLE1BQU0sSUFBSSxHQUFHLElBQUksSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxlQUFnQixDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLENBQUMsQ0FBQztnQkFDaEYsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDdEMsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDdEMsQ0FBQyxDQUFDLElBQUksR0FBRyxHQUFHLENBQUM7Z0JBQ2IsQ0FBQyxDQUFDLFFBQVEsR0FBRyxnQkFBZ0IsQ0FBQztnQkFDOUIsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNWLEdBQUcsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDM0IsQ0FBQzs7O3FCQUdRLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQywwQkFBMEIsRUFBRSxJQUFJLENBQUM7OztPQUduRyxDQUFDLENBQUMsQ0FBQyxFQUFFOztvQ0FFd0IsVUFBVTs7UUFFdEMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUE7Ozs7c0NBSWlCLE1BQU0sQ0FBQyxNQUFNOzs7O3NDQUliLE1BQU0sQ0FBQyxZQUFZOzs7O3NDQUluQixNQUFNLENBQUMsY0FBYzs7WUFFL0MsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUE7Ozt3RkFHOEMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLFdBQVc7O1dBRWhILENBQUMsQ0FBQyxDQUFDLEVBQUU7O09BRVQsQ0FBQyxDQUFDLENBQUMsRUFBRTs7O29CQUdRLGFBQWE7b0JBQ2Isb0RBQW9EO2dCQUN4RCxPQUFPOzJCQUNJLENBQUMsTUFBa0MsRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDMUQsV0FBVyxFQUFFLE1BQU0sQ0FBQyxRQUFRO2dCQUM1QixRQUFRLEVBQUUsTUFBTSxDQUFDLE9BQU87b0JBQ3RCLENBQUMsQ0FBQyxJQUFJLENBQUEsa0RBQWtEO29CQUN4RCxDQUFDLENBQUMsSUFBSSxDQUFBLG9EQUFvRDtnQkFDNUQsUUFBUSxFQUFFLE1BQU0sQ0FBQyxVQUFVLElBQUksR0FBRztnQkFDbEMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEVBQUUsTUFBTTtvQkFDekIsQ0FBQyxDQUFDLElBQUksQ0FBQSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFBLDBCQUEwQixDQUFDLFNBQVMsQ0FBQyxFQUFFO29CQUN6RSxDQUFDLENBQUMsR0FBRztnQkFDUCxhQUFhLEVBQUUsTUFBTSxDQUFDLFdBQVcsSUFBSSxHQUFHO2dCQUN4QyxTQUFTLEVBQUUsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLGtCQUFrQixFQUFFO2FBQzNELENBQUM7dUJBQ2E7Z0JBQ2I7b0JBQ0UsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsUUFBUSxFQUFFLGNBQWM7b0JBQ3hCLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBa0MsRUFBRSxFQUFFO3dCQUNuRCxNQUFNLFFBQVEsQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRTs0QkFDekUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFROzRCQUN6QixPQUFPLEVBQUUsQ0FBQyxNQUFNLENBQUMsT0FBTzt5QkFDekIsQ0FBQyxDQUFDO29CQUNMLENBQUM7aUJBQ0Y7Z0JBQ0Q7b0JBQ0UsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsUUFBUSxFQUFFLGVBQWU7b0JBQ3pCLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBa0MsRUFBRSxFQUFFO3dCQUNuRCxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsNkJBQTZCLENBQUMsQ0FBQzt3QkFDbEUsU0FBUyxDQUFDLGFBQWEsQ0FBQzs0QkFDdEIsT0FBTyxFQUFFLG1CQUFtQjs0QkFDNUIsT0FBTyxFQUFFLElBQUksQ0FBQSw4Q0FBOEMsTUFBTSxDQUFDLFFBQVEsUUFBUTs0QkFDbEYsV0FBVyxFQUFFO2dDQUNYLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQVUsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFO2dDQUNqRTtvQ0FDRSxJQUFJLEVBQUUsUUFBUTtvQ0FDZCxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQVUsRUFBRSxFQUFFO3dDQUMzQixNQUFNLFFBQVEsQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7d0NBQzVGLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQ0FDbEIsQ0FBQztpQ0FDRjs2QkFDRjt5QkFDRixDQUFDLENBQUM7b0JBQ0wsQ0FBQztpQkFDRjthQUNGO3lCQUNnQixLQUFLLElBQUksRUFBRTtnQkFDMUIsTUFBTSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsYUFBYSxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsNkJBQTZCLENBQUMsQ0FBQztnQkFDM0YsU0FBUyxDQUFDLGFBQWEsQ0FBQztvQkFDdEIsT0FBTyxFQUFFLG1CQUFtQjtvQkFDNUIsT0FBTyxFQUFFLElBQUksQ0FBQTs7d0RBRStCLFdBQVcsU0FBUyxVQUFVOzJEQUMzQixhQUFhLFNBQVMsYUFBYTtvREFDMUMsd0JBQXdCLFNBQVMsTUFBTTs7YUFFOUU7b0JBQ0QsV0FBVyxFQUFFO3dCQUNYLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQVUsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFO3dCQUNqRTs0QkFDRSxJQUFJLEVBQUUsUUFBUTs0QkFDZCxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQVUsRUFBRSxFQUFFO2dDQUMzQixNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsVUFBVyxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQVEsQ0FBQztnQ0FDakUsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7Z0NBQzFDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7Z0NBQ3ZHLE1BQU0sUUFBUSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLHFCQUFxQixFQUFFO29DQUN6RSxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7b0NBQ3ZCLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVyxJQUFJLFNBQVM7b0NBQzFDLElBQUk7aUNBQ0wsQ0FBQyxDQUFDO2dDQUNILEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQzs0QkFDbEIsQ0FBQzt5QkFDRjtxQkFDRjtpQkFDRixDQUFDLENBQUM7WUFDTCxDQUFDOztLQUVKLENBQUM7UUFDSixDQUFDOztZQW5UVSx1REFBVTs7Ozs7U0FBVixVQUFVIn0=
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serve.zone/dcrouter",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "11.
|
|
4
|
+
"version": "11.13.0",
|
|
5
5
|
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@push.rocks/lik": "^6.4.0",
|
|
41
41
|
"@push.rocks/projectinfo": "^5.1.0",
|
|
42
42
|
"@push.rocks/qenv": "^6.1.3",
|
|
43
|
-
"@push.rocks/smartacme": "^9.3.
|
|
43
|
+
"@push.rocks/smartacme": "^9.3.1",
|
|
44
44
|
"@push.rocks/smartdata": "^7.1.3",
|
|
45
45
|
"@push.rocks/smartdb": "^2.0.0",
|
|
46
46
|
"@push.rocks/smartdns": "^7.9.0",
|
|
@@ -53,12 +53,13 @@
|
|
|
53
53
|
"@push.rocks/smartnetwork": "^4.5.2",
|
|
54
54
|
"@push.rocks/smartpath": "^6.0.0",
|
|
55
55
|
"@push.rocks/smartpromise": "^4.2.3",
|
|
56
|
-
"@push.rocks/smartproxy": "^27.
|
|
56
|
+
"@push.rocks/smartproxy": "^27.1.0",
|
|
57
57
|
"@push.rocks/smartradius": "^1.1.1",
|
|
58
58
|
"@push.rocks/smartrequest": "^5.0.1",
|
|
59
59
|
"@push.rocks/smartrx": "^3.0.10",
|
|
60
60
|
"@push.rocks/smartstate": "^2.3.0",
|
|
61
61
|
"@push.rocks/smartunique": "^3.0.9",
|
|
62
|
+
"@push.rocks/smartvpn": "1.12.0",
|
|
62
63
|
"@push.rocks/taskbuffer": "^8.0.2",
|
|
63
64
|
"@serve.zone/catalog": "^2.9.0",
|
|
64
65
|
"@serve.zone/interfaces": "^5.3.0",
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/classes.dcrouter.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { OpsServer } from './opsserver/index.js';
|
|
|
22
22
|
import { MetricsManager } from './monitoring/index.js';
|
|
23
23
|
import { RadiusServer, type IRadiusServerConfig } from './radius/index.js';
|
|
24
24
|
import { RemoteIngressManager, TunnelManager } from './remoteingress/index.js';
|
|
25
|
+
import { VpnManager, type IVpnManagerConfig } from './vpn/index.js';
|
|
25
26
|
import { RouteConfigManager, ApiTokenManager } from './config/index.js';
|
|
26
27
|
import { SecurityLogger, ContentScanner, IPReputationChecker } from './security/index.js';
|
|
27
28
|
import { type IHttp3Config, augmentRoutesWithHttp3 } from './http3/index.js';
|
|
@@ -188,6 +189,26 @@ export interface IDcRouterOptions {
|
|
|
188
189
|
keyPath?: string;
|
|
189
190
|
};
|
|
190
191
|
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* VPN server configuration.
|
|
195
|
+
* Enables VPN-based access control: routes with vpn.required are only
|
|
196
|
+
* accessible from VPN clients. Supports WireGuard + native (WS/QUIC) transports.
|
|
197
|
+
*/
|
|
198
|
+
vpnConfig?: {
|
|
199
|
+
/** Enable VPN server (default: false) */
|
|
200
|
+
enabled?: boolean;
|
|
201
|
+
/** VPN subnet CIDR (default: '10.8.0.0/24') */
|
|
202
|
+
subnet?: string;
|
|
203
|
+
/** WireGuard UDP listen port (default: 51820) */
|
|
204
|
+
wgListenPort?: number;
|
|
205
|
+
/** DNS servers pushed to VPN clients */
|
|
206
|
+
dns?: string[];
|
|
207
|
+
/** Server endpoint hostname for client configs (e.g. 'vpn.example.com') */
|
|
208
|
+
serverEndpoint?: string;
|
|
209
|
+
/** Override forwarding mode. Default: auto-detect (tun if root, socket otherwise) */
|
|
210
|
+
forwardingMode?: 'tun' | 'socket';
|
|
211
|
+
};
|
|
191
212
|
}
|
|
192
213
|
|
|
193
214
|
/**
|
|
@@ -226,6 +247,9 @@ export class DcRouter {
|
|
|
226
247
|
public remoteIngressManager?: RemoteIngressManager;
|
|
227
248
|
public tunnelManager?: TunnelManager;
|
|
228
249
|
|
|
250
|
+
// VPN
|
|
251
|
+
public vpnManager?: VpnManager;
|
|
252
|
+
|
|
229
253
|
// Programmatic config API
|
|
230
254
|
public routeConfigManager?: RouteConfigManager;
|
|
231
255
|
public apiTokenManager?: ApiTokenManager;
|
|
@@ -429,6 +453,7 @@ export class DcRouter {
|
|
|
429
453
|
() => this.getConstructorRoutes(),
|
|
430
454
|
() => this.smartProxy,
|
|
431
455
|
() => this.options.http3,
|
|
456
|
+
() => this.options.vpnConfig?.enabled ? (this.options.vpnConfig.subnet || '10.8.0.0/24') : undefined,
|
|
432
457
|
);
|
|
433
458
|
this.apiTokenManager = new ApiTokenManager(this.storageManager);
|
|
434
459
|
await this.apiTokenManager.initialize();
|
|
@@ -533,6 +558,25 @@ export class DcRouter {
|
|
|
533
558
|
);
|
|
534
559
|
}
|
|
535
560
|
|
|
561
|
+
// VPN Server: optional, depends on SmartProxy
|
|
562
|
+
if (this.options.vpnConfig?.enabled) {
|
|
563
|
+
this.serviceManager.addService(
|
|
564
|
+
new plugins.taskbuffer.Service('VpnServer')
|
|
565
|
+
.optional()
|
|
566
|
+
.dependsOn('SmartProxy')
|
|
567
|
+
.withStart(async () => {
|
|
568
|
+
await this.setupVpnServer();
|
|
569
|
+
})
|
|
570
|
+
.withStop(async () => {
|
|
571
|
+
if (this.vpnManager) {
|
|
572
|
+
await this.vpnManager.stop();
|
|
573
|
+
this.vpnManager = undefined;
|
|
574
|
+
}
|
|
575
|
+
})
|
|
576
|
+
.withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }),
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
|
|
536
580
|
// Wire up aggregated events for logging
|
|
537
581
|
this.serviceSubjectSubscription = this.serviceManager.serviceSubject.subscribe((event) => {
|
|
538
582
|
const level = event.type === 'failed' ? 'error' : event.type === 'retrying' ? 'warn' : 'info';
|
|
@@ -616,6 +660,15 @@ export class DcRouter {
|
|
|
616
660
|
logger.log('info', `RADIUS Service: auth=${this.options.radiusConfig.authPort || 1812}, acct=${this.options.radiusConfig.acctPort || 1813}, clients=${this.options.radiusConfig.clients?.length || 0}, VLANs=${vlanStats.totalMappings}, accounting=${this.options.radiusConfig.accounting?.enabled ? 'enabled' : 'disabled'}`);
|
|
617
661
|
}
|
|
618
662
|
|
|
663
|
+
// VPN summary
|
|
664
|
+
if (this.vpnManager && this.options.vpnConfig?.enabled) {
|
|
665
|
+
const subnet = this.vpnManager.getSubnet();
|
|
666
|
+
const wgPort = this.options.vpnConfig.wgListenPort ?? 51820;
|
|
667
|
+
const mode = this.vpnManager.forwardingMode;
|
|
668
|
+
const clientCount = this.vpnManager.listClients().length;
|
|
669
|
+
logger.log('info', `VPN Service: mode=${mode}, subnet=${subnet}, wg=:${wgPort}, clients=${clientCount}`);
|
|
670
|
+
}
|
|
671
|
+
|
|
619
672
|
// Remote Ingress summary
|
|
620
673
|
if (this.tunnelManager && this.options.remoteIngressConfig?.enabled) {
|
|
621
674
|
const edgeCount = this.remoteIngressManager?.getAllEdges().length || 0;
|
|
@@ -741,6 +794,11 @@ export class DcRouter {
|
|
|
741
794
|
logger.log('info', 'HTTP/3: Augmented qualifying HTTPS routes with QUIC/H3 configuration');
|
|
742
795
|
}
|
|
743
796
|
|
|
797
|
+
// VPN route security injection: restrict vpn.required routes to VPN subnet
|
|
798
|
+
if (this.options.vpnConfig?.enabled) {
|
|
799
|
+
routes = this.injectVpnSecurity(routes);
|
|
800
|
+
}
|
|
801
|
+
|
|
744
802
|
// Cache constructor routes for RouteConfigManager
|
|
745
803
|
this.constructorRoutes = [...routes];
|
|
746
804
|
|
|
@@ -852,14 +910,22 @@ export class DcRouter {
|
|
|
852
910
|
const cert = await this.smartAcme!.getCertificateForDomain(domain, {
|
|
853
911
|
includeWildcard: !isWildcardDomain,
|
|
854
912
|
});
|
|
855
|
-
|
|
856
|
-
|
|
913
|
+
// Parse real X509 expiry from PEM (defense-in-depth over SmartAcme's estimate)
|
|
914
|
+
let realValidUntil = cert.validUntil;
|
|
915
|
+
if (cert.publicKey) {
|
|
916
|
+
try {
|
|
917
|
+
const x509 = new plugins.crypto.X509Certificate(cert.publicKey);
|
|
918
|
+
realValidUntil = new Date(x509.validTo).getTime();
|
|
919
|
+
} catch { /* fallback to SmartAcme's value */ }
|
|
920
|
+
}
|
|
921
|
+
if (realValidUntil) {
|
|
922
|
+
eventComms.setExpiryDate(new Date(realValidUntil));
|
|
857
923
|
}
|
|
858
924
|
const result = {
|
|
859
925
|
id: cert.id,
|
|
860
926
|
domainName: cert.domainName,
|
|
861
927
|
created: cert.created,
|
|
862
|
-
validUntil:
|
|
928
|
+
validUntil: realValidUntil,
|
|
863
929
|
privateKey: cert.privateKey,
|
|
864
930
|
publicKey: cert.publicKey,
|
|
865
931
|
csr: cert.csr,
|
|
@@ -884,6 +950,22 @@ export class DcRouter {
|
|
|
884
950
|
smartProxyConfig.proxyIPs = ['127.0.0.1'];
|
|
885
951
|
}
|
|
886
952
|
|
|
953
|
+
// When VPN is in socket mode, the userspace NAT engine sends PP v2 headers
|
|
954
|
+
// on outbound connections to SmartProxy to preserve VPN client tunnel IPs.
|
|
955
|
+
if (this.options.vpnConfig?.enabled) {
|
|
956
|
+
const vpnForwardingMode = this.options.vpnConfig.forwardingMode
|
|
957
|
+
?? (process.getuid?.() === 0 ? 'tun' : 'socket');
|
|
958
|
+
if (vpnForwardingMode === 'socket') {
|
|
959
|
+
smartProxyConfig.acceptProxyProtocol = true;
|
|
960
|
+
if (!smartProxyConfig.proxyIPs) {
|
|
961
|
+
smartProxyConfig.proxyIPs = [];
|
|
962
|
+
}
|
|
963
|
+
if (!smartProxyConfig.proxyIPs.includes('127.0.0.1')) {
|
|
964
|
+
smartProxyConfig.proxyIPs.push('127.0.0.1');
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
887
969
|
// Create SmartProxy instance
|
|
888
970
|
logger.log('info', `Creating SmartProxy instance: routes=${smartProxyConfig.routes?.length}, acme=${smartProxyConfig.acme?.enabled}, certProvisionFunction=${!!smartProxyConfig.certProvisionFunction}`);
|
|
889
971
|
|
|
@@ -1988,6 +2070,58 @@ export class DcRouter {
|
|
|
1988
2070
|
logger.log('info', `Remote Ingress hub started on port ${this.options.remoteIngressConfig.tunnelPort || 8443} with ${edgeCount} registered edge(s)`);
|
|
1989
2071
|
}
|
|
1990
2072
|
|
|
2073
|
+
/**
|
|
2074
|
+
* Set up VPN server for VPN-based route access control.
|
|
2075
|
+
*/
|
|
2076
|
+
private async setupVpnServer(): Promise<void> {
|
|
2077
|
+
if (!this.options.vpnConfig?.enabled) {
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
logger.log('info', 'Setting up VPN server...');
|
|
2082
|
+
|
|
2083
|
+
this.vpnManager = new VpnManager(this.storageManager, {
|
|
2084
|
+
subnet: this.options.vpnConfig.subnet,
|
|
2085
|
+
wgListenPort: this.options.vpnConfig.wgListenPort,
|
|
2086
|
+
dns: this.options.vpnConfig.dns,
|
|
2087
|
+
serverEndpoint: this.options.vpnConfig.serverEndpoint,
|
|
2088
|
+
forwardingMode: this.options.vpnConfig.forwardingMode,
|
|
2089
|
+
});
|
|
2090
|
+
|
|
2091
|
+
await this.vpnManager.start();
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
/**
|
|
2095
|
+
* Inject VPN security into routes that have vpn.required === true.
|
|
2096
|
+
* Adds the VPN subnet to security.ipAllowList so only VPN clients can access them.
|
|
2097
|
+
*/
|
|
2098
|
+
private injectVpnSecurity(routes: plugins.smartproxy.IRouteConfig[]): plugins.smartproxy.IRouteConfig[] {
|
|
2099
|
+
const vpnSubnet = this.options.vpnConfig?.subnet || '10.8.0.0/24';
|
|
2100
|
+
let injectedCount = 0;
|
|
2101
|
+
|
|
2102
|
+
const result = routes.map((route) => {
|
|
2103
|
+
const dcrouterRoute = route as import('../ts_interfaces/data/remoteingress.js').IDcRouterRouteConfig;
|
|
2104
|
+
if (dcrouterRoute.vpn?.required) {
|
|
2105
|
+
injectedCount++;
|
|
2106
|
+
const existing = route.security?.ipAllowList || [];
|
|
2107
|
+
return {
|
|
2108
|
+
...route,
|
|
2109
|
+
security: {
|
|
2110
|
+
...route.security,
|
|
2111
|
+
ipAllowList: [...existing, vpnSubnet],
|
|
2112
|
+
},
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
return route;
|
|
2116
|
+
});
|
|
2117
|
+
|
|
2118
|
+
if (injectedCount > 0) {
|
|
2119
|
+
logger.log('info', `VPN: Injected ipAllowList (${vpnSubnet}) into ${injectedCount} VPN-protected route(s)`);
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
return result;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
1991
2125
|
/**
|
|
1992
2126
|
* Set up RADIUS server for network authentication
|
|
1993
2127
|
*/
|