@serve.zone/dcrouter 13.21.1 → 13.23.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 +26 -4
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +6 -0
- package/dist_ts/classes.dcrouter.js +83 -5
- package/dist_ts/config/classes.route-config-manager.d.ts +1 -1
- package/dist_ts/config/classes.route-config-manager.js +2 -2
- package/dist_ts/db/documents/classes.ip-intelligence.doc.d.ts +25 -0
- package/dist_ts/db/documents/classes.ip-intelligence.doc.js +175 -0
- package/dist_ts/db/documents/classes.security-block-rule.doc.d.ts +17 -0
- package/dist_ts/db/documents/classes.security-block-rule.doc.js +124 -0
- package/dist_ts/db/documents/classes.security-policy-audit.doc.d.ts +11 -0
- package/dist_ts/db/documents/classes.security-policy-audit.doc.js +95 -0
- package/dist_ts/db/documents/index.d.ts +3 -0
- package/dist_ts/db/documents/index.js +4 -1
- package/dist_ts/monitoring/classes.metricsmanager.js +2 -1
- package/dist_ts/opsserver/handlers/config.handler.js +2 -1
- package/dist_ts/opsserver/handlers/remoteingress.handler.js +3 -1
- package/dist_ts/opsserver/handlers/security.handler.js +42 -1
- package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +10 -0
- package/dist_ts/remoteingress/classes.remoteingress-manager.js +9 -1
- package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +3 -0
- package/dist_ts/remoteingress/classes.tunnel-manager.js +23 -5
- package/dist_ts/security/classes.security-policy-manager.d.ts +41 -0
- package/dist_ts/security/classes.security-policy-manager.js +283 -0
- package/dist_ts/security/index.d.ts +1 -0
- package/dist_ts/security/index.js +2 -1
- package/dist_ts_apiclient/classes.remoteingress.d.ts +2 -0
- package/dist_ts_apiclient/classes.remoteingress.js +7 -1
- 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 +51 -0
- package/dist_ts_interfaces/data/security-policy.d.ts +32 -0
- package/dist_ts_interfaces/data/security-policy.js +2 -0
- package/dist_ts_interfaces/requests/config.d.ts +1 -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/security-policy.d.ts +64 -0
- package/dist_ts_interfaces/requests/security-policy.js +2 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/network/ops-view-remoteingress.d.ts +5 -0
- package/dist_ts_web/elements/network/ops-view-remoteingress.js +69 -1
- package/package.json +3 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +106 -6
- package/ts/config/classes.route-config-manager.ts +2 -2
- package/ts/db/documents/classes.ip-intelligence.doc.ts +75 -0
- package/ts/db/documents/classes.security-block-rule.doc.ts +52 -0
- package/ts/db/documents/classes.security-policy-audit.doc.ts +33 -0
- package/ts/db/documents/index.ts +3 -0
- package/ts/monitoring/classes.metricsmanager.ts +2 -0
- package/ts/opsserver/handlers/config.handler.ts +1 -0
- package/ts/opsserver/handlers/remoteingress.handler.ts +2 -0
- package/ts/opsserver/handlers/security.handler.ts +69 -0
- package/ts/remoteingress/classes.remoteingress-manager.ts +15 -2
- package/ts/remoteingress/classes.tunnel-manager.ts +25 -5
- package/ts/security/classes.security-policy-manager.ts +315 -0
- package/ts/security/index.ts +7 -1
- package/ts_apiclient/classes.remoteingress.ts +6 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/network/ops-view-remoteingress.ts +68 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
|
3
|
+
import type { IIpIntelligenceRecord } from '../../../ts_interfaces/data/security-policy.js';
|
|
4
|
+
|
|
5
|
+
const getDb = () => DcRouterDb.getInstance().getDb();
|
|
6
|
+
|
|
7
|
+
@plugins.smartdata.Collection(() => getDb())
|
|
8
|
+
export class IpIntelligenceDoc extends plugins.smartdata.SmartDataDbDoc<IpIntelligenceDoc, IpIntelligenceDoc> implements IIpIntelligenceRecord {
|
|
9
|
+
@plugins.smartdata.unI()
|
|
10
|
+
@plugins.smartdata.svDb()
|
|
11
|
+
public ipAddress!: string;
|
|
12
|
+
|
|
13
|
+
@plugins.smartdata.svDb()
|
|
14
|
+
public asn: number | null = null;
|
|
15
|
+
|
|
16
|
+
@plugins.smartdata.svDb()
|
|
17
|
+
public asnOrg: string | null = null;
|
|
18
|
+
|
|
19
|
+
@plugins.smartdata.svDb()
|
|
20
|
+
public registrantOrg: string | null = null;
|
|
21
|
+
|
|
22
|
+
@plugins.smartdata.svDb()
|
|
23
|
+
public registrantCountry: string | null = null;
|
|
24
|
+
|
|
25
|
+
@plugins.smartdata.svDb()
|
|
26
|
+
public networkRange: string | null = null;
|
|
27
|
+
|
|
28
|
+
@plugins.smartdata.svDb()
|
|
29
|
+
public abuseContact: string | null = null;
|
|
30
|
+
|
|
31
|
+
@plugins.smartdata.svDb()
|
|
32
|
+
public country: string | null = null;
|
|
33
|
+
|
|
34
|
+
@plugins.smartdata.svDb()
|
|
35
|
+
public countryCode: string | null = null;
|
|
36
|
+
|
|
37
|
+
@plugins.smartdata.svDb()
|
|
38
|
+
public city: string | null = null;
|
|
39
|
+
|
|
40
|
+
@plugins.smartdata.svDb()
|
|
41
|
+
public latitude: number | null = null;
|
|
42
|
+
|
|
43
|
+
@plugins.smartdata.svDb()
|
|
44
|
+
public longitude: number | null = null;
|
|
45
|
+
|
|
46
|
+
@plugins.smartdata.svDb()
|
|
47
|
+
public accuracyRadius: number | null = null;
|
|
48
|
+
|
|
49
|
+
@plugins.smartdata.svDb()
|
|
50
|
+
public timezone: string | null = null;
|
|
51
|
+
|
|
52
|
+
@plugins.smartdata.svDb()
|
|
53
|
+
public firstSeenAt: number = Date.now();
|
|
54
|
+
|
|
55
|
+
@plugins.smartdata.svDb()
|
|
56
|
+
public lastSeenAt: number = Date.now();
|
|
57
|
+
|
|
58
|
+
@plugins.smartdata.svDb()
|
|
59
|
+
public updatedAt: number = Date.now();
|
|
60
|
+
|
|
61
|
+
@plugins.smartdata.svDb()
|
|
62
|
+
public seenCount: number = 0;
|
|
63
|
+
|
|
64
|
+
constructor() {
|
|
65
|
+
super();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public static async findByIp(ipAddress: string): Promise<IpIntelligenceDoc | null> {
|
|
69
|
+
return await IpIntelligenceDoc.getInstance({ ipAddress });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public static async findAll(): Promise<IpIntelligenceDoc[]> {
|
|
73
|
+
return await IpIntelligenceDoc.getInstances({});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
|
3
|
+
import type { ISecurityBlockRule, TSecurityBlockRuleMatchMode, TSecurityBlockRuleType } from '../../../ts_interfaces/data/security-policy.js';
|
|
4
|
+
|
|
5
|
+
const getDb = () => DcRouterDb.getInstance().getDb();
|
|
6
|
+
|
|
7
|
+
@plugins.smartdata.Collection(() => getDb())
|
|
8
|
+
export class SecurityBlockRuleDoc extends plugins.smartdata.SmartDataDbDoc<SecurityBlockRuleDoc, SecurityBlockRuleDoc> implements ISecurityBlockRule {
|
|
9
|
+
@plugins.smartdata.unI()
|
|
10
|
+
@plugins.smartdata.svDb()
|
|
11
|
+
public id!: string;
|
|
12
|
+
|
|
13
|
+
@plugins.smartdata.svDb()
|
|
14
|
+
public type!: TSecurityBlockRuleType;
|
|
15
|
+
|
|
16
|
+
@plugins.smartdata.svDb()
|
|
17
|
+
public value!: string;
|
|
18
|
+
|
|
19
|
+
@plugins.smartdata.svDb()
|
|
20
|
+
public matchMode?: TSecurityBlockRuleMatchMode;
|
|
21
|
+
|
|
22
|
+
@plugins.smartdata.svDb()
|
|
23
|
+
public enabled: boolean = true;
|
|
24
|
+
|
|
25
|
+
@plugins.smartdata.svDb()
|
|
26
|
+
public reason?: string;
|
|
27
|
+
|
|
28
|
+
@plugins.smartdata.svDb()
|
|
29
|
+
public createdAt: number = Date.now();
|
|
30
|
+
|
|
31
|
+
@plugins.smartdata.svDb()
|
|
32
|
+
public updatedAt: number = Date.now();
|
|
33
|
+
|
|
34
|
+
@plugins.smartdata.svDb()
|
|
35
|
+
public createdBy: string = 'system';
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public static async findById(id: string): Promise<SecurityBlockRuleDoc | null> {
|
|
42
|
+
return await SecurityBlockRuleDoc.getInstance({ id });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public static async findAll(): Promise<SecurityBlockRuleDoc[]> {
|
|
46
|
+
return await SecurityBlockRuleDoc.getInstances({});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public static async findEnabled(): Promise<SecurityBlockRuleDoc[]> {
|
|
50
|
+
return await SecurityBlockRuleDoc.getInstances({ enabled: true });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
|
3
|
+
import type { ISecurityPolicyAuditEvent } from '../../../ts_interfaces/data/security-policy.js';
|
|
4
|
+
|
|
5
|
+
const getDb = () => DcRouterDb.getInstance().getDb();
|
|
6
|
+
|
|
7
|
+
@plugins.smartdata.Collection(() => getDb())
|
|
8
|
+
export class SecurityPolicyAuditDoc extends plugins.smartdata.SmartDataDbDoc<SecurityPolicyAuditDoc, SecurityPolicyAuditDoc> implements ISecurityPolicyAuditEvent {
|
|
9
|
+
@plugins.smartdata.unI()
|
|
10
|
+
@plugins.smartdata.svDb()
|
|
11
|
+
public id!: string;
|
|
12
|
+
|
|
13
|
+
@plugins.smartdata.svDb()
|
|
14
|
+
public action!: string;
|
|
15
|
+
|
|
16
|
+
@plugins.smartdata.svDb()
|
|
17
|
+
public actor!: string;
|
|
18
|
+
|
|
19
|
+
@plugins.smartdata.svDb()
|
|
20
|
+
public details!: Record<string, unknown>;
|
|
21
|
+
|
|
22
|
+
@plugins.smartdata.svDb()
|
|
23
|
+
public createdAt: number = Date.now();
|
|
24
|
+
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public static async findRecent(limit = 100): Promise<SecurityPolicyAuditDoc[]> {
|
|
30
|
+
const docs = await SecurityPolicyAuditDoc.getInstances({});
|
|
31
|
+
return docs.sort((a, b) => b.createdAt - a.createdAt).slice(0, limit);
|
|
32
|
+
}
|
|
33
|
+
}
|
package/ts/db/documents/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// Cached/TTL document classes
|
|
2
2
|
export * from './classes.cached.email.js';
|
|
3
3
|
export * from './classes.cached.ip.reputation.js';
|
|
4
|
+
export * from './classes.ip-intelligence.doc.js';
|
|
5
|
+
export * from './classes.security-block-rule.doc.js';
|
|
6
|
+
export * from './classes.security-policy-audit.doc.js';
|
|
4
7
|
|
|
5
8
|
// Config document classes
|
|
6
9
|
export * from './classes.route.doc.js';
|
|
@@ -725,6 +725,8 @@ export class MetricsManager {
|
|
|
725
725
|
.slice(0, 10)
|
|
726
726
|
.map(([ip, data]) => ({ ip, count: data.count, bwIn: data.bwIn, bwOut: data.bwOut }));
|
|
727
727
|
|
|
728
|
+
void this.dcRouter.securityPolicyManager?.observeIps([...allIPData.keys()]);
|
|
729
|
+
|
|
728
730
|
// Build domain activity using per-IP domain request counts from Rust engine
|
|
729
731
|
const connectionsByRoute = proxyMetrics.connections.byRoute();
|
|
730
732
|
const throughputByRoute = proxyMetrics.throughput.byRoute();
|
|
@@ -29,6 +29,7 @@ export class RemoteIngressHandler {
|
|
|
29
29
|
...e,
|
|
30
30
|
secret: '********', // Never expose secrets via API
|
|
31
31
|
effectiveListenPorts: manager.getEffectiveListenPorts(e),
|
|
32
|
+
effectiveListenPortsUdp: manager.getEffectiveListenPortsUdp(e),
|
|
32
33
|
manualPorts: breakdown.manual,
|
|
33
34
|
derivedPorts: breakdown.derived,
|
|
34
35
|
};
|
|
@@ -133,6 +134,7 @@ export class RemoteIngressHandler {
|
|
|
133
134
|
...edge,
|
|
134
135
|
secret: '********',
|
|
135
136
|
effectiveListenPorts: manager.getEffectiveListenPorts(edge),
|
|
137
|
+
effectiveListenPortsUdp: manager.getEffectiveListenPortsUdp(edge),
|
|
136
138
|
manualPorts: breakdown.manual,
|
|
137
139
|
derivedPorts: breakdown.derived,
|
|
138
140
|
},
|
|
@@ -157,6 +157,75 @@ export class SecurityHandler {
|
|
|
157
157
|
}
|
|
158
158
|
)
|
|
159
159
|
);
|
|
160
|
+
|
|
161
|
+
router.addTypedHandler(
|
|
162
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ListSecurityBlockRules>(
|
|
163
|
+
'listSecurityBlockRules',
|
|
164
|
+
async () => {
|
|
165
|
+
const manager = this.opsServerRef.dcRouterRef.securityPolicyManager;
|
|
166
|
+
return { rules: manager ? await manager.listBlockRules() : [] };
|
|
167
|
+
},
|
|
168
|
+
),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
router.addTypedHandler(
|
|
172
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ListIpIntelligence>(
|
|
173
|
+
'listIpIntelligence',
|
|
174
|
+
async () => {
|
|
175
|
+
const manager = this.opsServerRef.dcRouterRef.securityPolicyManager;
|
|
176
|
+
return { records: manager ? await manager.listIpIntelligence() : [] };
|
|
177
|
+
},
|
|
178
|
+
),
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const adminRouter = this.opsServerRef.adminRouter;
|
|
182
|
+
|
|
183
|
+
adminRouter.addTypedHandler(
|
|
184
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateSecurityBlockRule>(
|
|
185
|
+
'createSecurityBlockRule',
|
|
186
|
+
async (dataArg) => {
|
|
187
|
+
const manager = this.opsServerRef.dcRouterRef.securityPolicyManager;
|
|
188
|
+
if (!manager) return { success: false, message: 'Security policy manager not initialized' };
|
|
189
|
+
const rule = await manager.createBlockRule({
|
|
190
|
+
type: dataArg.type,
|
|
191
|
+
value: dataArg.value,
|
|
192
|
+
matchMode: dataArg.matchMode,
|
|
193
|
+
reason: dataArg.reason,
|
|
194
|
+
enabled: dataArg.enabled,
|
|
195
|
+
}, dataArg.identity.userId);
|
|
196
|
+
return { success: true, rule };
|
|
197
|
+
},
|
|
198
|
+
),
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
adminRouter.addTypedHandler(
|
|
202
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateSecurityBlockRule>(
|
|
203
|
+
'updateSecurityBlockRule',
|
|
204
|
+
async (dataArg) => {
|
|
205
|
+
const manager = this.opsServerRef.dcRouterRef.securityPolicyManager;
|
|
206
|
+
if (!manager) return { success: false, message: 'Security policy manager not initialized' };
|
|
207
|
+
const rule = await manager.updateBlockRule(dataArg.id, {
|
|
208
|
+
value: dataArg.value,
|
|
209
|
+
matchMode: dataArg.matchMode,
|
|
210
|
+
reason: dataArg.reason,
|
|
211
|
+
enabled: dataArg.enabled,
|
|
212
|
+
}, dataArg.identity.userId);
|
|
213
|
+
return rule ? { success: true, rule } : { success: false, message: 'Rule not found' };
|
|
214
|
+
},
|
|
215
|
+
),
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
adminRouter.addTypedHandler(
|
|
219
|
+
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteSecurityBlockRule>(
|
|
220
|
+
'deleteSecurityBlockRule',
|
|
221
|
+
async (dataArg) => {
|
|
222
|
+
const manager = this.opsServerRef.dcRouterRef.securityPolicyManager;
|
|
223
|
+
if (!manager) return { success: false, message: 'Security policy manager not initialized' };
|
|
224
|
+
const success = await manager.deleteBlockRule(dataArg.id, dataArg.identity.userId);
|
|
225
|
+
return { success, message: success ? undefined : 'Rule not found' };
|
|
226
|
+
},
|
|
227
|
+
),
|
|
228
|
+
);
|
|
160
229
|
}
|
|
161
230
|
|
|
162
231
|
private async collectSecurityMetrics(): Promise<{
|
|
@@ -2,6 +2,10 @@ import * as plugins from '../plugins.js';
|
|
|
2
2
|
import type { IRemoteIngress, IDcRouterRouteConfig } from '../../ts_interfaces/data/remoteingress.js';
|
|
3
3
|
import { RemoteIngressEdgeDoc } from '../db/index.js';
|
|
4
4
|
|
|
5
|
+
interface IRemoteIngressFirewallConfig {
|
|
6
|
+
blockedIps?: string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
/**
|
|
6
10
|
* Flatten a port range (number | number[] | Array<{from, to}>) to a sorted unique number array.
|
|
7
11
|
*/
|
|
@@ -31,6 +35,7 @@ function extractPorts(portRange: number | Array<number | { from: number; to: num
|
|
|
31
35
|
export class RemoteIngressManager {
|
|
32
36
|
private edges: Map<string, IRemoteIngress> = new Map();
|
|
33
37
|
private routes: IDcRouterRouteConfig[] = [];
|
|
38
|
+
private firewallConfig?: IRemoteIngressFirewallConfig;
|
|
34
39
|
|
|
35
40
|
constructor() {
|
|
36
41
|
}
|
|
@@ -69,6 +74,13 @@ export class RemoteIngressManager {
|
|
|
69
74
|
this.routes = routes;
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Set the full desired firewall snapshot pushed to all edges.
|
|
79
|
+
*/
|
|
80
|
+
public setFirewallConfig(firewallConfig?: IRemoteIngressFirewallConfig): void {
|
|
81
|
+
this.firewallConfig = firewallConfig;
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
/**
|
|
73
85
|
* Derive listen ports for an edge from routes tagged with remoteIngress.enabled.
|
|
74
86
|
* When a route specifies edgeFilter, only edges whose id or tags match get that route's ports.
|
|
@@ -305,8 +317,8 @@ export class RemoteIngressManager {
|
|
|
305
317
|
* Get the list of allowed edges (enabled only) for the Rust hub.
|
|
306
318
|
* Includes listenPortsUdp when routes with transport 'udp' or 'all' are present.
|
|
307
319
|
*/
|
|
308
|
-
public getAllowedEdges(): Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[] }> {
|
|
309
|
-
const result: Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[] }> = [];
|
|
320
|
+
public getAllowedEdges(): Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[]; firewallConfig?: IRemoteIngressFirewallConfig }> {
|
|
321
|
+
const result: Array<{ id: string; secret: string; listenPorts: number[]; listenPortsUdp?: number[]; firewallConfig?: IRemoteIngressFirewallConfig }> = [];
|
|
310
322
|
for (const edge of this.edges.values()) {
|
|
311
323
|
if (edge.enabled) {
|
|
312
324
|
const listenPortsUdp = this.getEffectiveListenPortsUdp(edge);
|
|
@@ -315,6 +327,7 @@ export class RemoteIngressManager {
|
|
|
315
327
|
secret: edge.secret,
|
|
316
328
|
listenPorts: this.getEffectiveListenPorts(edge),
|
|
317
329
|
...(listenPortsUdp.length > 0 ? { listenPortsUdp } : {}),
|
|
330
|
+
...(this.firewallConfig ? { firewallConfig: this.firewallConfig } : {}),
|
|
318
331
|
});
|
|
319
332
|
}
|
|
320
333
|
}
|
|
@@ -9,6 +9,7 @@ export interface ITunnelManagerConfig {
|
|
|
9
9
|
certPem?: string;
|
|
10
10
|
keyPem?: string;
|
|
11
11
|
};
|
|
12
|
+
performance?: import('../../ts_interfaces/data/remoteingress.js').IRemoteIngressPerformanceConfig;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -20,6 +21,7 @@ export class TunnelManager {
|
|
|
20
21
|
private config: ITunnelManagerConfig;
|
|
21
22
|
private edgeStatuses: Map<string, IRemoteIngressStatus> = new Map();
|
|
22
23
|
private reconcileInterval: ReturnType<typeof setInterval> | null = null;
|
|
24
|
+
private syncChain: Promise<void> = Promise.resolve();
|
|
23
25
|
|
|
24
26
|
constructor(manager: RemoteIngressManager, config: ITunnelManagerConfig = {}) {
|
|
25
27
|
this.manager = manager;
|
|
@@ -66,7 +68,8 @@ export class TunnelManager {
|
|
|
66
68
|
tunnelPort: this.config.tunnelPort ?? 8443,
|
|
67
69
|
targetHost: this.config.targetHost ?? '127.0.0.1',
|
|
68
70
|
tls: this.config.tls,
|
|
69
|
-
|
|
71
|
+
...(this.config.performance ? { performance: this.config.performance } : {}),
|
|
72
|
+
} as any);
|
|
70
73
|
|
|
71
74
|
// Send allowed edges to the hub
|
|
72
75
|
await this.syncAllowedEdges();
|
|
@@ -107,20 +110,23 @@ export class TunnelManager {
|
|
|
107
110
|
if (existing) {
|
|
108
111
|
existing.activeTunnels = rustEdge.activeStreams;
|
|
109
112
|
existing.lastHeartbeat = Date.now();
|
|
113
|
+
this.applyRustStatus(existing, rustEdge);
|
|
110
114
|
// Update peer address if available from Rust hub
|
|
111
115
|
if (rustEdge.peerAddr) {
|
|
112
116
|
existing.publicIp = rustEdge.peerAddr;
|
|
113
117
|
}
|
|
114
118
|
} else {
|
|
115
119
|
// Missed edgeConnected event — add entry
|
|
116
|
-
|
|
120
|
+
const status: IRemoteIngressStatus = {
|
|
117
121
|
edgeId: rustEdge.edgeId,
|
|
118
122
|
connected: true,
|
|
119
123
|
publicIp: rustEdge.peerAddr || null,
|
|
120
124
|
activeTunnels: rustEdge.activeStreams,
|
|
121
125
|
lastHeartbeat: Date.now(),
|
|
122
126
|
connectedAt: rustEdge.connectedAt * 1000,
|
|
123
|
-
}
|
|
127
|
+
};
|
|
128
|
+
this.applyRustStatus(status, rustEdge);
|
|
129
|
+
this.edgeStatuses.set(rustEdge.edgeId, status);
|
|
124
130
|
}
|
|
125
131
|
}
|
|
126
132
|
|
|
@@ -137,8 +143,22 @@ export class TunnelManager {
|
|
|
137
143
|
* Call this after creating/deleting/updating edges.
|
|
138
144
|
*/
|
|
139
145
|
public async syncAllowedEdges(): Promise<void> {
|
|
140
|
-
const
|
|
141
|
-
|
|
146
|
+
const run = this.syncChain.catch(() => {}).then(async () => {
|
|
147
|
+
const edges = this.manager.getAllowedEdges();
|
|
148
|
+
await this.hub.updateAllowedEdges(edges as any);
|
|
149
|
+
});
|
|
150
|
+
this.syncChain = run;
|
|
151
|
+
await run;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private applyRustStatus(status: IRemoteIngressStatus, rustEdge: any): void {
|
|
155
|
+
status.transportMode = rustEdge.transportMode;
|
|
156
|
+
status.fallbackUsed = rustEdge.fallbackUsed;
|
|
157
|
+
status.performance = rustEdge.performance;
|
|
158
|
+
status.flowControl = rustEdge.flowControl;
|
|
159
|
+
status.queues = rustEdge.queues;
|
|
160
|
+
status.traffic = rustEdge.traffic;
|
|
161
|
+
status.udp = rustEdge.udp;
|
|
142
162
|
}
|
|
143
163
|
|
|
144
164
|
/**
|