@serve.zone/dcrouter 12.1.0 → 12.2.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 +750 -688
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +6 -1
- package/dist_ts/classes.dcrouter.js +11 -3
- package/dist_ts/config/classes.db-seeder.d.ts +25 -0
- package/dist_ts/config/classes.db-seeder.js +69 -0
- package/dist_ts/config/classes.reference-resolver.d.ts +80 -0
- package/dist_ts/config/classes.reference-resolver.js +482 -0
- package/dist_ts/config/classes.route-config-manager.d.ts +13 -3
- package/dist_ts/config/classes.route-config-manager.js +53 -3
- package/dist_ts/config/index.d.ts +2 -0
- package/dist_ts/config/index.js +3 -1
- package/dist_ts/db/documents/classes.network-target.doc.d.ts +15 -0
- package/dist_ts/db/documents/classes.network-target.doc.js +118 -0
- package/dist_ts/db/documents/classes.security-profile.doc.d.ts +16 -0
- package/dist_ts/db/documents/classes.security-profile.doc.js +118 -0
- package/dist_ts/db/documents/classes.stored-route.doc.d.ts +2 -0
- package/dist_ts/db/documents/classes.stored-route.doc.js +8 -2
- package/dist_ts/db/documents/index.d.ts +2 -0
- package/dist_ts/db/documents/index.js +3 -1
- package/dist_ts/opsserver/classes.opsserver.d.ts +2 -0
- package/dist_ts/opsserver/classes.opsserver.js +5 -1
- package/dist_ts/opsserver/handlers/index.d.ts +2 -0
- package/dist_ts/opsserver/handlers/index.js +3 -1
- package/dist_ts/opsserver/handlers/network-target.handler.d.ts +10 -0
- package/dist_ts/opsserver/handlers/network-target.handler.js +117 -0
- package/dist_ts/opsserver/handlers/route-management.handler.js +3 -2
- package/dist_ts/opsserver/handlers/security-profile.handler.d.ts +10 -0
- package/dist_ts/opsserver/handlers/security-profile.handler.js +119 -0
- package/dist_ts_interfaces/data/route-management.d.ts +48 -1
- package/dist_ts_interfaces/requests/index.d.ts +2 -0
- package/dist_ts_interfaces/requests/index.js +3 -1
- package/dist_ts_interfaces/requests/network-targets.d.ts +102 -0
- package/dist_ts_interfaces/requests/network-targets.js +2 -0
- package/dist_ts_interfaces/requests/route-management.d.ts +3 -1
- package/dist_ts_interfaces/requests/security-profiles.d.ts +102 -0
- package/dist_ts_interfaces/requests/security-profiles.js +2 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +43 -0
- package/dist_ts_web/appstate.js +176 -2
- package/dist_ts_web/elements/index.d.ts +2 -0
- package/dist_ts_web/elements/index.js +3 -1
- package/dist_ts_web/elements/ops-dashboard.js +13 -1
- package/dist_ts_web/elements/ops-view-networktargets.d.ts +17 -0
- package/dist_ts_web/elements/ops-view-networktargets.js +246 -0
- package/dist_ts_web/elements/ops-view-securityprofiles.d.ts +17 -0
- package/dist_ts_web/elements/ops-view-securityprofiles.js +275 -0
- package/dist_ts_web/router.d.ts +1 -1
- package/dist_ts_web/router.js +2 -2
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +19 -1
- package/ts/config/classes.db-seeder.ts +95 -0
- package/ts/config/classes.reference-resolver.ts +576 -0
- package/ts/config/classes.route-config-manager.ts +64 -1
- package/ts/config/index.ts +3 -1
- package/ts/db/documents/classes.network-target.doc.ts +48 -0
- package/ts/db/documents/classes.security-profile.doc.ts +49 -0
- package/ts/db/documents/classes.stored-route.doc.ts +4 -0
- package/ts/db/documents/index.ts +2 -0
- package/ts/opsserver/classes.opsserver.ts +4 -0
- package/ts/opsserver/handlers/index.ts +3 -1
- package/ts/opsserver/handlers/network-target.handler.ts +167 -0
- package/ts/opsserver/handlers/route-management.handler.ts +2 -1
- package/ts/opsserver/handlers/security-profile.handler.ts +169 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +243 -1
- package/ts_web/elements/index.ts +2 -0
- package/ts_web/elements/ops-dashboard.ts +12 -0
- package/ts_web/elements/ops-view-networktargets.ts +214 -0
- package/ts_web/elements/ops-view-securityprofiles.ts +242 -0
- package/ts_web/router.ts +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import type { ISecurityProfile, INetworkTarget, IRouteMetadata, IStoredRoute, IRouteSecurity } from '../../dist_ts_interfaces/data/route-management.js';
|
|
3
|
+
export declare class ReferenceResolver {
|
|
4
|
+
private profiles;
|
|
5
|
+
private targets;
|
|
6
|
+
initialize(): Promise<void>;
|
|
7
|
+
createProfile(data: {
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
security: IRouteSecurity;
|
|
11
|
+
extendsProfiles?: string[];
|
|
12
|
+
createdBy: string;
|
|
13
|
+
}): Promise<string>;
|
|
14
|
+
updateProfile(id: string, patch: Partial<Omit<ISecurityProfile, 'id' | 'createdAt' | 'createdBy'>>): Promise<{
|
|
15
|
+
affectedRouteIds: string[];
|
|
16
|
+
}>;
|
|
17
|
+
deleteProfile(id: string, force: boolean, storedRoutes?: Map<string, IStoredRoute>): Promise<{
|
|
18
|
+
success: boolean;
|
|
19
|
+
message?: string;
|
|
20
|
+
}>;
|
|
21
|
+
getProfile(id: string): ISecurityProfile | undefined;
|
|
22
|
+
getProfileByName(name: string): ISecurityProfile | undefined;
|
|
23
|
+
listProfiles(): ISecurityProfile[];
|
|
24
|
+
getProfileUsage(storedRoutes: Map<string, IStoredRoute>): Map<string, Array<{
|
|
25
|
+
id: string;
|
|
26
|
+
routeName: string;
|
|
27
|
+
}>>;
|
|
28
|
+
getProfileUsageForId(profileId: string, storedRoutes: Map<string, IStoredRoute>): Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
routeName: string;
|
|
31
|
+
}>;
|
|
32
|
+
createTarget(data: {
|
|
33
|
+
name: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
host: string | string[];
|
|
36
|
+
port: number;
|
|
37
|
+
createdBy: string;
|
|
38
|
+
}): Promise<string>;
|
|
39
|
+
updateTarget(id: string, patch: Partial<Omit<INetworkTarget, 'id' | 'createdAt' | 'createdBy'>>): Promise<{
|
|
40
|
+
affectedRouteIds: string[];
|
|
41
|
+
}>;
|
|
42
|
+
deleteTarget(id: string, force: boolean, storedRoutes?: Map<string, IStoredRoute>): Promise<{
|
|
43
|
+
success: boolean;
|
|
44
|
+
message?: string;
|
|
45
|
+
}>;
|
|
46
|
+
getTarget(id: string): INetworkTarget | undefined;
|
|
47
|
+
getTargetByName(name: string): INetworkTarget | undefined;
|
|
48
|
+
listTargets(): INetworkTarget[];
|
|
49
|
+
getTargetUsageForId(targetId: string, storedRoutes: Map<string, IStoredRoute>): Array<{
|
|
50
|
+
id: string;
|
|
51
|
+
routeName: string;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve references for a single route.
|
|
55
|
+
* Materializes security profile and/or network target into the route's fields.
|
|
56
|
+
* Returns the resolved route and updated metadata.
|
|
57
|
+
*/
|
|
58
|
+
resolveRoute(route: plugins.smartproxy.IRouteConfig, metadata?: IRouteMetadata): {
|
|
59
|
+
route: plugins.smartproxy.IRouteConfig;
|
|
60
|
+
metadata: IRouteMetadata;
|
|
61
|
+
};
|
|
62
|
+
findRoutesByProfileRef(profileId: string): Promise<string[]>;
|
|
63
|
+
findRoutesByTargetRef(targetId: string): Promise<string[]>;
|
|
64
|
+
findRoutesByProfileRefSync(profileId: string, storedRoutes: Map<string, IStoredRoute>): string[];
|
|
65
|
+
findRoutesByTargetRefSync(targetId: string, storedRoutes: Map<string, IStoredRoute>): string[];
|
|
66
|
+
private resolveSecurityProfile;
|
|
67
|
+
/**
|
|
68
|
+
* Merge two IRouteSecurity objects.
|
|
69
|
+
* `override` values take precedence over `base` values.
|
|
70
|
+
* For ipAllowList/ipBlockList: union arrays and deduplicate.
|
|
71
|
+
* For scalar/object fields: override wins if present.
|
|
72
|
+
*/
|
|
73
|
+
private mergeSecurityFields;
|
|
74
|
+
private loadProfiles;
|
|
75
|
+
private loadTargets;
|
|
76
|
+
private persistProfile;
|
|
77
|
+
private persistTarget;
|
|
78
|
+
private clearProfileRefsOnRoutes;
|
|
79
|
+
private clearTargetRefsOnRoutes;
|
|
80
|
+
}
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
import { SecurityProfileDoc, NetworkTargetDoc, StoredRouteDoc } from '../db/index.js';
|
|
4
|
+
const MAX_INHERITANCE_DEPTH = 5;
|
|
5
|
+
export class ReferenceResolver {
|
|
6
|
+
profiles = new Map();
|
|
7
|
+
targets = new Map();
|
|
8
|
+
// =========================================================================
|
|
9
|
+
// Lifecycle
|
|
10
|
+
// =========================================================================
|
|
11
|
+
async initialize() {
|
|
12
|
+
await this.loadProfiles();
|
|
13
|
+
await this.loadTargets();
|
|
14
|
+
}
|
|
15
|
+
// =========================================================================
|
|
16
|
+
// Profile CRUD
|
|
17
|
+
// =========================================================================
|
|
18
|
+
async createProfile(data) {
|
|
19
|
+
const id = plugins.uuid.v4();
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
const profile = {
|
|
22
|
+
id,
|
|
23
|
+
name: data.name,
|
|
24
|
+
description: data.description,
|
|
25
|
+
security: data.security,
|
|
26
|
+
extendsProfiles: data.extendsProfiles,
|
|
27
|
+
createdAt: now,
|
|
28
|
+
updatedAt: now,
|
|
29
|
+
createdBy: data.createdBy,
|
|
30
|
+
};
|
|
31
|
+
this.profiles.set(id, profile);
|
|
32
|
+
await this.persistProfile(profile);
|
|
33
|
+
logger.log('info', `Created security profile '${profile.name}' (${id})`);
|
|
34
|
+
return id;
|
|
35
|
+
}
|
|
36
|
+
async updateProfile(id, patch) {
|
|
37
|
+
const profile = this.profiles.get(id);
|
|
38
|
+
if (!profile) {
|
|
39
|
+
throw new Error(`Security profile '${id}' not found`);
|
|
40
|
+
}
|
|
41
|
+
if (patch.name !== undefined)
|
|
42
|
+
profile.name = patch.name;
|
|
43
|
+
if (patch.description !== undefined)
|
|
44
|
+
profile.description = patch.description;
|
|
45
|
+
if (patch.security !== undefined)
|
|
46
|
+
profile.security = patch.security;
|
|
47
|
+
if (patch.extendsProfiles !== undefined)
|
|
48
|
+
profile.extendsProfiles = patch.extendsProfiles;
|
|
49
|
+
profile.updatedAt = Date.now();
|
|
50
|
+
await this.persistProfile(profile);
|
|
51
|
+
logger.log('info', `Updated security profile '${profile.name}' (${id})`);
|
|
52
|
+
// Find routes referencing this profile
|
|
53
|
+
const affectedRouteIds = await this.findRoutesByProfileRef(id);
|
|
54
|
+
return { affectedRouteIds };
|
|
55
|
+
}
|
|
56
|
+
async deleteProfile(id, force, storedRoutes) {
|
|
57
|
+
const profile = this.profiles.get(id);
|
|
58
|
+
if (!profile) {
|
|
59
|
+
return { success: false, message: `Security profile '${id}' not found` };
|
|
60
|
+
}
|
|
61
|
+
// Check usage
|
|
62
|
+
const affectedIds = storedRoutes
|
|
63
|
+
? this.findRoutesByProfileRefSync(id, storedRoutes)
|
|
64
|
+
: await this.findRoutesByProfileRef(id);
|
|
65
|
+
if (affectedIds.length > 0 && !force) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
message: `Profile '${profile.name}' is in use by ${affectedIds.length} route(s). Use force=true to delete.`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Delete from DB
|
|
72
|
+
const doc = await SecurityProfileDoc.findById(id);
|
|
73
|
+
if (doc)
|
|
74
|
+
await doc.delete();
|
|
75
|
+
this.profiles.delete(id);
|
|
76
|
+
// If force-deleting with referencing routes, clear refs but keep resolved values
|
|
77
|
+
if (affectedIds.length > 0) {
|
|
78
|
+
await this.clearProfileRefsOnRoutes(affectedIds);
|
|
79
|
+
logger.log('warn', `Force-deleted profile '${profile.name}'; cleared refs on ${affectedIds.length} route(s)`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
logger.log('info', `Deleted security profile '${profile.name}' (${id})`);
|
|
83
|
+
}
|
|
84
|
+
return { success: true };
|
|
85
|
+
}
|
|
86
|
+
getProfile(id) {
|
|
87
|
+
return this.profiles.get(id);
|
|
88
|
+
}
|
|
89
|
+
getProfileByName(name) {
|
|
90
|
+
for (const profile of this.profiles.values()) {
|
|
91
|
+
if (profile.name === name)
|
|
92
|
+
return profile;
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
listProfiles() {
|
|
97
|
+
return [...this.profiles.values()];
|
|
98
|
+
}
|
|
99
|
+
getProfileUsage(storedRoutes) {
|
|
100
|
+
const usage = new Map();
|
|
101
|
+
for (const profile of this.profiles.values()) {
|
|
102
|
+
usage.set(profile.id, []);
|
|
103
|
+
}
|
|
104
|
+
for (const [routeId, stored] of storedRoutes) {
|
|
105
|
+
const ref = stored.metadata?.securityProfileRef;
|
|
106
|
+
if (ref && usage.has(ref)) {
|
|
107
|
+
usage.get(ref).push({ id: routeId, routeName: stored.route.name || routeId });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return usage;
|
|
111
|
+
}
|
|
112
|
+
getProfileUsageForId(profileId, storedRoutes) {
|
|
113
|
+
const routes = [];
|
|
114
|
+
for (const [routeId, stored] of storedRoutes) {
|
|
115
|
+
if (stored.metadata?.securityProfileRef === profileId) {
|
|
116
|
+
routes.push({ id: routeId, routeName: stored.route.name || routeId });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return routes;
|
|
120
|
+
}
|
|
121
|
+
// =========================================================================
|
|
122
|
+
// Target CRUD
|
|
123
|
+
// =========================================================================
|
|
124
|
+
async createTarget(data) {
|
|
125
|
+
const id = plugins.uuid.v4();
|
|
126
|
+
const now = Date.now();
|
|
127
|
+
const target = {
|
|
128
|
+
id,
|
|
129
|
+
name: data.name,
|
|
130
|
+
description: data.description,
|
|
131
|
+
host: data.host,
|
|
132
|
+
port: data.port,
|
|
133
|
+
createdAt: now,
|
|
134
|
+
updatedAt: now,
|
|
135
|
+
createdBy: data.createdBy,
|
|
136
|
+
};
|
|
137
|
+
this.targets.set(id, target);
|
|
138
|
+
await this.persistTarget(target);
|
|
139
|
+
logger.log('info', `Created network target '${target.name}' (${id})`);
|
|
140
|
+
return id;
|
|
141
|
+
}
|
|
142
|
+
async updateTarget(id, patch) {
|
|
143
|
+
const target = this.targets.get(id);
|
|
144
|
+
if (!target) {
|
|
145
|
+
throw new Error(`Network target '${id}' not found`);
|
|
146
|
+
}
|
|
147
|
+
if (patch.name !== undefined)
|
|
148
|
+
target.name = patch.name;
|
|
149
|
+
if (patch.description !== undefined)
|
|
150
|
+
target.description = patch.description;
|
|
151
|
+
if (patch.host !== undefined)
|
|
152
|
+
target.host = patch.host;
|
|
153
|
+
if (patch.port !== undefined)
|
|
154
|
+
target.port = patch.port;
|
|
155
|
+
target.updatedAt = Date.now();
|
|
156
|
+
await this.persistTarget(target);
|
|
157
|
+
logger.log('info', `Updated network target '${target.name}' (${id})`);
|
|
158
|
+
const affectedRouteIds = await this.findRoutesByTargetRef(id);
|
|
159
|
+
return { affectedRouteIds };
|
|
160
|
+
}
|
|
161
|
+
async deleteTarget(id, force, storedRoutes) {
|
|
162
|
+
const target = this.targets.get(id);
|
|
163
|
+
if (!target) {
|
|
164
|
+
return { success: false, message: `Network target '${id}' not found` };
|
|
165
|
+
}
|
|
166
|
+
const affectedIds = storedRoutes
|
|
167
|
+
? this.findRoutesByTargetRefSync(id, storedRoutes)
|
|
168
|
+
: await this.findRoutesByTargetRef(id);
|
|
169
|
+
if (affectedIds.length > 0 && !force) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
message: `Target '${target.name}' is in use by ${affectedIds.length} route(s). Use force=true to delete.`,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const doc = await NetworkTargetDoc.findById(id);
|
|
176
|
+
if (doc)
|
|
177
|
+
await doc.delete();
|
|
178
|
+
this.targets.delete(id);
|
|
179
|
+
if (affectedIds.length > 0) {
|
|
180
|
+
await this.clearTargetRefsOnRoutes(affectedIds);
|
|
181
|
+
logger.log('warn', `Force-deleted target '${target.name}'; cleared refs on ${affectedIds.length} route(s)`);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
logger.log('info', `Deleted network target '${target.name}' (${id})`);
|
|
185
|
+
}
|
|
186
|
+
return { success: true };
|
|
187
|
+
}
|
|
188
|
+
getTarget(id) {
|
|
189
|
+
return this.targets.get(id);
|
|
190
|
+
}
|
|
191
|
+
getTargetByName(name) {
|
|
192
|
+
for (const target of this.targets.values()) {
|
|
193
|
+
if (target.name === name)
|
|
194
|
+
return target;
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
listTargets() {
|
|
199
|
+
return [...this.targets.values()];
|
|
200
|
+
}
|
|
201
|
+
getTargetUsageForId(targetId, storedRoutes) {
|
|
202
|
+
const routes = [];
|
|
203
|
+
for (const [routeId, stored] of storedRoutes) {
|
|
204
|
+
if (stored.metadata?.networkTargetRef === targetId) {
|
|
205
|
+
routes.push({ id: routeId, routeName: stored.route.name || routeId });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return routes;
|
|
209
|
+
}
|
|
210
|
+
// =========================================================================
|
|
211
|
+
// Resolution
|
|
212
|
+
// =========================================================================
|
|
213
|
+
/**
|
|
214
|
+
* Resolve references for a single route.
|
|
215
|
+
* Materializes security profile and/or network target into the route's fields.
|
|
216
|
+
* Returns the resolved route and updated metadata.
|
|
217
|
+
*/
|
|
218
|
+
resolveRoute(route, metadata) {
|
|
219
|
+
const resolvedMetadata = { ...metadata };
|
|
220
|
+
if (resolvedMetadata.securityProfileRef) {
|
|
221
|
+
const resolvedSecurity = this.resolveSecurityProfile(resolvedMetadata.securityProfileRef);
|
|
222
|
+
if (resolvedSecurity) {
|
|
223
|
+
const profile = this.profiles.get(resolvedMetadata.securityProfileRef);
|
|
224
|
+
// Merge: profile provides base, route's inline values override
|
|
225
|
+
route = {
|
|
226
|
+
...route,
|
|
227
|
+
security: this.mergeSecurityFields(resolvedSecurity, route.security),
|
|
228
|
+
};
|
|
229
|
+
resolvedMetadata.securityProfileName = profile?.name;
|
|
230
|
+
resolvedMetadata.lastResolvedAt = Date.now();
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
logger.log('warn', `Security profile '${resolvedMetadata.securityProfileRef}' not found during resolution`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (resolvedMetadata.networkTargetRef) {
|
|
237
|
+
const target = this.targets.get(resolvedMetadata.networkTargetRef);
|
|
238
|
+
if (target) {
|
|
239
|
+
route = {
|
|
240
|
+
...route,
|
|
241
|
+
action: {
|
|
242
|
+
...route.action,
|
|
243
|
+
targets: [{
|
|
244
|
+
host: target.host,
|
|
245
|
+
port: target.port,
|
|
246
|
+
}],
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
resolvedMetadata.networkTargetName = target.name;
|
|
250
|
+
resolvedMetadata.lastResolvedAt = Date.now();
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
logger.log('warn', `Network target '${resolvedMetadata.networkTargetRef}' not found during resolution`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return { route, metadata: resolvedMetadata };
|
|
257
|
+
}
|
|
258
|
+
// =========================================================================
|
|
259
|
+
// Reference lookup helpers
|
|
260
|
+
// =========================================================================
|
|
261
|
+
async findRoutesByProfileRef(profileId) {
|
|
262
|
+
const docs = await StoredRouteDoc.findAll();
|
|
263
|
+
return docs
|
|
264
|
+
.filter((doc) => doc.metadata?.securityProfileRef === profileId)
|
|
265
|
+
.map((doc) => doc.id);
|
|
266
|
+
}
|
|
267
|
+
async findRoutesByTargetRef(targetId) {
|
|
268
|
+
const docs = await StoredRouteDoc.findAll();
|
|
269
|
+
return docs
|
|
270
|
+
.filter((doc) => doc.metadata?.networkTargetRef === targetId)
|
|
271
|
+
.map((doc) => doc.id);
|
|
272
|
+
}
|
|
273
|
+
findRoutesByProfileRefSync(profileId, storedRoutes) {
|
|
274
|
+
const ids = [];
|
|
275
|
+
for (const [routeId, stored] of storedRoutes) {
|
|
276
|
+
if (stored.metadata?.securityProfileRef === profileId) {
|
|
277
|
+
ids.push(routeId);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return ids;
|
|
281
|
+
}
|
|
282
|
+
findRoutesByTargetRefSync(targetId, storedRoutes) {
|
|
283
|
+
const ids = [];
|
|
284
|
+
for (const [routeId, stored] of storedRoutes) {
|
|
285
|
+
if (stored.metadata?.networkTargetRef === targetId) {
|
|
286
|
+
ids.push(routeId);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return ids;
|
|
290
|
+
}
|
|
291
|
+
// =========================================================================
|
|
292
|
+
// Private: security profile resolution with inheritance
|
|
293
|
+
// =========================================================================
|
|
294
|
+
resolveSecurityProfile(profileId, visited = new Set(), depth = 0) {
|
|
295
|
+
if (depth > MAX_INHERITANCE_DEPTH) {
|
|
296
|
+
logger.log('warn', `Max inheritance depth (${MAX_INHERITANCE_DEPTH}) exceeded resolving profile '${profileId}'`);
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
if (visited.has(profileId)) {
|
|
300
|
+
logger.log('warn', `Circular inheritance detected for profile '${profileId}'`);
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
const profile = this.profiles.get(profileId);
|
|
304
|
+
if (!profile)
|
|
305
|
+
return null;
|
|
306
|
+
visited.add(profileId);
|
|
307
|
+
// Start with an empty base
|
|
308
|
+
let baseSecurity = {};
|
|
309
|
+
// Resolve parent profiles first (top-down, later overrides earlier)
|
|
310
|
+
if (profile.extendsProfiles?.length) {
|
|
311
|
+
for (const parentId of profile.extendsProfiles) {
|
|
312
|
+
const parentSecurity = this.resolveSecurityProfile(parentId, new Set(visited), depth + 1);
|
|
313
|
+
if (parentSecurity) {
|
|
314
|
+
baseSecurity = this.mergeSecurityFields(baseSecurity, parentSecurity);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// Apply this profile's security on top
|
|
319
|
+
return this.mergeSecurityFields(baseSecurity, profile.security);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Merge two IRouteSecurity objects.
|
|
323
|
+
* `override` values take precedence over `base` values.
|
|
324
|
+
* For ipAllowList/ipBlockList: union arrays and deduplicate.
|
|
325
|
+
* For scalar/object fields: override wins if present.
|
|
326
|
+
*/
|
|
327
|
+
mergeSecurityFields(base, override) {
|
|
328
|
+
if (!base && !override)
|
|
329
|
+
return {};
|
|
330
|
+
if (!base)
|
|
331
|
+
return { ...override };
|
|
332
|
+
if (!override)
|
|
333
|
+
return { ...base };
|
|
334
|
+
const merged = { ...base };
|
|
335
|
+
// IP lists: union
|
|
336
|
+
if (override.ipAllowList || base.ipAllowList) {
|
|
337
|
+
merged.ipAllowList = [...new Set([
|
|
338
|
+
...(base.ipAllowList || []),
|
|
339
|
+
...(override.ipAllowList || []),
|
|
340
|
+
])];
|
|
341
|
+
}
|
|
342
|
+
if (override.ipBlockList || base.ipBlockList) {
|
|
343
|
+
merged.ipBlockList = [...new Set([
|
|
344
|
+
...(base.ipBlockList || []),
|
|
345
|
+
...(override.ipBlockList || []),
|
|
346
|
+
])];
|
|
347
|
+
}
|
|
348
|
+
// Scalar/object fields: override wins
|
|
349
|
+
if (override.maxConnections !== undefined)
|
|
350
|
+
merged.maxConnections = override.maxConnections;
|
|
351
|
+
if (override.rateLimit !== undefined)
|
|
352
|
+
merged.rateLimit = override.rateLimit;
|
|
353
|
+
if (override.authentication !== undefined)
|
|
354
|
+
merged.authentication = override.authentication;
|
|
355
|
+
if (override.basicAuth !== undefined)
|
|
356
|
+
merged.basicAuth = override.basicAuth;
|
|
357
|
+
if (override.jwtAuth !== undefined)
|
|
358
|
+
merged.jwtAuth = override.jwtAuth;
|
|
359
|
+
return merged;
|
|
360
|
+
}
|
|
361
|
+
// =========================================================================
|
|
362
|
+
// Private: persistence
|
|
363
|
+
// =========================================================================
|
|
364
|
+
async loadProfiles() {
|
|
365
|
+
const docs = await SecurityProfileDoc.findAll();
|
|
366
|
+
for (const doc of docs) {
|
|
367
|
+
if (doc.id) {
|
|
368
|
+
this.profiles.set(doc.id, {
|
|
369
|
+
id: doc.id,
|
|
370
|
+
name: doc.name,
|
|
371
|
+
description: doc.description,
|
|
372
|
+
security: doc.security,
|
|
373
|
+
extendsProfiles: doc.extendsProfiles,
|
|
374
|
+
createdAt: doc.createdAt,
|
|
375
|
+
updatedAt: doc.updatedAt,
|
|
376
|
+
createdBy: doc.createdBy,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (this.profiles.size > 0) {
|
|
381
|
+
logger.log('info', `Loaded ${this.profiles.size} security profile(s) from storage`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async loadTargets() {
|
|
385
|
+
const docs = await NetworkTargetDoc.findAll();
|
|
386
|
+
for (const doc of docs) {
|
|
387
|
+
if (doc.id) {
|
|
388
|
+
this.targets.set(doc.id, {
|
|
389
|
+
id: doc.id,
|
|
390
|
+
name: doc.name,
|
|
391
|
+
description: doc.description,
|
|
392
|
+
host: doc.host,
|
|
393
|
+
port: doc.port,
|
|
394
|
+
createdAt: doc.createdAt,
|
|
395
|
+
updatedAt: doc.updatedAt,
|
|
396
|
+
createdBy: doc.createdBy,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (this.targets.size > 0) {
|
|
401
|
+
logger.log('info', `Loaded ${this.targets.size} network target(s) from storage`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async persistProfile(profile) {
|
|
405
|
+
const existingDoc = await SecurityProfileDoc.findById(profile.id);
|
|
406
|
+
if (existingDoc) {
|
|
407
|
+
existingDoc.name = profile.name;
|
|
408
|
+
existingDoc.description = profile.description;
|
|
409
|
+
existingDoc.security = profile.security;
|
|
410
|
+
existingDoc.extendsProfiles = profile.extendsProfiles;
|
|
411
|
+
existingDoc.updatedAt = profile.updatedAt;
|
|
412
|
+
await existingDoc.save();
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
const doc = new SecurityProfileDoc();
|
|
416
|
+
doc.id = profile.id;
|
|
417
|
+
doc.name = profile.name;
|
|
418
|
+
doc.description = profile.description;
|
|
419
|
+
doc.security = profile.security;
|
|
420
|
+
doc.extendsProfiles = profile.extendsProfiles;
|
|
421
|
+
doc.createdAt = profile.createdAt;
|
|
422
|
+
doc.updatedAt = profile.updatedAt;
|
|
423
|
+
doc.createdBy = profile.createdBy;
|
|
424
|
+
await doc.save();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async persistTarget(target) {
|
|
428
|
+
const existingDoc = await NetworkTargetDoc.findById(target.id);
|
|
429
|
+
if (existingDoc) {
|
|
430
|
+
existingDoc.name = target.name;
|
|
431
|
+
existingDoc.description = target.description;
|
|
432
|
+
existingDoc.host = target.host;
|
|
433
|
+
existingDoc.port = target.port;
|
|
434
|
+
existingDoc.updatedAt = target.updatedAt;
|
|
435
|
+
await existingDoc.save();
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
const doc = new NetworkTargetDoc();
|
|
439
|
+
doc.id = target.id;
|
|
440
|
+
doc.name = target.name;
|
|
441
|
+
doc.description = target.description;
|
|
442
|
+
doc.host = target.host;
|
|
443
|
+
doc.port = target.port;
|
|
444
|
+
doc.createdAt = target.createdAt;
|
|
445
|
+
doc.updatedAt = target.updatedAt;
|
|
446
|
+
doc.createdBy = target.createdBy;
|
|
447
|
+
await doc.save();
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
// =========================================================================
|
|
451
|
+
// Private: ref cleanup on force-delete
|
|
452
|
+
// =========================================================================
|
|
453
|
+
async clearProfileRefsOnRoutes(routeIds) {
|
|
454
|
+
for (const routeId of routeIds) {
|
|
455
|
+
const doc = await StoredRouteDoc.findById(routeId);
|
|
456
|
+
if (doc?.metadata) {
|
|
457
|
+
doc.metadata = {
|
|
458
|
+
...doc.metadata,
|
|
459
|
+
securityProfileRef: undefined,
|
|
460
|
+
securityProfileName: undefined,
|
|
461
|
+
};
|
|
462
|
+
doc.updatedAt = Date.now();
|
|
463
|
+
await doc.save();
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
async clearTargetRefsOnRoutes(routeIds) {
|
|
468
|
+
for (const routeId of routeIds) {
|
|
469
|
+
const doc = await StoredRouteDoc.findById(routeId);
|
|
470
|
+
if (doc?.metadata) {
|
|
471
|
+
doc.metadata = {
|
|
472
|
+
...doc.metadata,
|
|
473
|
+
networkTargetRef: undefined,
|
|
474
|
+
networkTargetName: undefined,
|
|
475
|
+
};
|
|
476
|
+
doc.updatedAt = Date.now();
|
|
477
|
+
await doc.save();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5yZWZlcmVuY2UtcmVzb2x2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb25maWcvY2xhc3Nlcy5yZWZlcmVuY2UtcmVzb2x2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFTdEYsTUFBTSxxQkFBcUIsR0FBRyxDQUFDLENBQUM7QUFFaEMsTUFBTSxPQUFPLGlCQUFpQjtJQUNwQixRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQTRCLENBQUM7SUFDL0MsT0FBTyxHQUFHLElBQUksR0FBRyxFQUEwQixDQUFDO0lBRXBELDRFQUE0RTtJQUM1RSxZQUFZO0lBQ1osNEVBQTRFO0lBRXJFLEtBQUssQ0FBQyxVQUFVO1FBQ3JCLE1BQU0sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQzFCLE1BQU0sSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRCw0RUFBNEU7SUFDNUUsZUFBZTtJQUNmLDRFQUE0RTtJQUVyRSxLQUFLLENBQUMsYUFBYSxDQUFDLElBTTFCO1FBQ0MsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUM3QixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFdkIsTUFBTSxPQUFPLEdBQXFCO1lBQ2hDLEVBQUU7WUFDRixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7WUFDZixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDN0IsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO1lBQ3ZCLGVBQWUsRUFBRSxJQUFJLENBQUMsZUFBZTtZQUNyQyxTQUFT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
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
|
-
import type { IMergedRoute, IRouteWarning } from '../../dist_ts_interfaces/data/route-management.js';
|
|
2
|
+
import type { IStoredRoute, IMergedRoute, IRouteWarning, IRouteMetadata } from '../../dist_ts_interfaces/data/route-management.js';
|
|
3
3
|
import { type IHttp3Config } from '../http3/index.js';
|
|
4
|
+
import type { ReferenceResolver } from './classes.reference-resolver.js';
|
|
4
5
|
export declare class RouteConfigManager {
|
|
5
6
|
private getHardcodedRoutes;
|
|
6
7
|
private getSmartProxy;
|
|
7
8
|
private getHttp3Config?;
|
|
8
9
|
private getVpnAllowList?;
|
|
10
|
+
private referenceResolver?;
|
|
9
11
|
private storedRoutes;
|
|
10
12
|
private overrides;
|
|
11
13
|
private warnings;
|
|
12
|
-
constructor(getHardcodedRoutes: () => plugins.smartproxy.IRouteConfig[], getSmartProxy: () => plugins.smartproxy.SmartProxy | undefined, getHttp3Config?: (() => IHttp3Config | undefined) | undefined, getVpnAllowList?: ((tags?: string[]) => string[]) | undefined);
|
|
14
|
+
constructor(getHardcodedRoutes: () => plugins.smartproxy.IRouteConfig[], getSmartProxy: () => plugins.smartproxy.SmartProxy | undefined, getHttp3Config?: (() => IHttp3Config | undefined) | undefined, getVpnAllowList?: ((tags?: string[]) => string[]) | undefined, referenceResolver?: ReferenceResolver | undefined);
|
|
15
|
+
/** Expose stored routes map for reference resolution lookups. */
|
|
16
|
+
getStoredRoutes(): Map<string, IStoredRoute>;
|
|
13
17
|
/**
|
|
14
18
|
* Load persisted routes and overrides, compute warnings, apply to SmartProxy.
|
|
15
19
|
*/
|
|
@@ -18,10 +22,11 @@ export declare class RouteConfigManager {
|
|
|
18
22
|
routes: IMergedRoute[];
|
|
19
23
|
warnings: IRouteWarning[];
|
|
20
24
|
};
|
|
21
|
-
createRoute(route: plugins.smartproxy.IRouteConfig, createdBy: string, enabled?: boolean): Promise<string>;
|
|
25
|
+
createRoute(route: plugins.smartproxy.IRouteConfig, createdBy: string, enabled?: boolean, metadata?: IRouteMetadata): Promise<string>;
|
|
22
26
|
updateRoute(id: string, patch: {
|
|
23
27
|
route?: Partial<plugins.smartproxy.IRouteConfig>;
|
|
24
28
|
enabled?: boolean;
|
|
29
|
+
metadata?: Partial<IRouteMetadata>;
|
|
25
30
|
}): Promise<boolean>;
|
|
26
31
|
deleteRoute(id: string): Promise<boolean>;
|
|
27
32
|
toggleRoute(id: string, enabled: boolean): Promise<boolean>;
|
|
@@ -32,5 +37,10 @@ export declare class RouteConfigManager {
|
|
|
32
37
|
private persistRoute;
|
|
33
38
|
private computeWarnings;
|
|
34
39
|
private logWarnings;
|
|
40
|
+
/**
|
|
41
|
+
* Re-resolve specific routes by ID (after a profile or target is updated).
|
|
42
|
+
* Persists each route and calls applyRoutes() once at the end.
|
|
43
|
+
*/
|
|
44
|
+
reResolveRoutes(routeIds: string[]): Promise<void>;
|
|
35
45
|
applyRoutes(): Promise<void>;
|
|
36
46
|
}
|