@serve.zone/dcrouter 13.41.1 → 13.42.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/deno.json +3 -3
- package/dist_serve/bundle.js +1025 -983
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/config/classes.db-seeder.js +29 -2
- package/dist_ts/config/classes.reference-resolver.d.ts +5 -0
- package/dist_ts/config/classes.reference-resolver.js +79 -15
- package/dist_ts/config/classes.route-config-manager.d.ts +5 -1
- package/dist_ts/config/classes.route-config-manager.js +136 -6
- package/dist_ts/config/classes.source-policy-compiler.d.ts +35 -0
- package/dist_ts/config/classes.source-policy-compiler.js +497 -0
- package/dist_ts/config/index.d.ts +1 -0
- package/dist_ts/config/index.js +2 -1
- package/dist_ts_interfaces/data/route-management.d.ts +39 -0
- package/dist_ts_interfaces/data/route-management.js +65 -1
- package/dist_ts_migrations/index.js +67 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/network/ops-view-routes.d.ts +2 -0
- package/dist_ts_web/elements/network/ops-view-routes.js +237 -11
- package/dist_ts_web/elements/network/ops-view-sourceprofiles.js +42 -5
- package/package.json +4 -4
- package/readme.md +74 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/config/classes.db-seeder.ts +28 -1
- package/ts/config/classes.reference-resolver.ts +94 -14
- package/ts/config/classes.route-config-manager.ts +162 -5
- package/ts/config/classes.source-policy-compiler.ts +614 -0
- package/ts/config/index.ts +1 -0
- package/ts/readme.md +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/network/ops-view-routes.ts +257 -10
- package/ts_web/elements/network/ops-view-sourceprofiles.ts +41 -4
|
@@ -37,6 +37,31 @@ import * as appstate from '../../appstate.js';
|
|
|
37
37
|
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
38
38
|
import { viewHostCss } from '../shared/css.js';
|
|
39
39
|
import {} from '@design.estate/dees-catalog';
|
|
40
|
+
function parseOptionalPositiveInteger(value) {
|
|
41
|
+
const parsed = typeof value === 'number'
|
|
42
|
+
? value
|
|
43
|
+
: typeof value === 'string'
|
|
44
|
+
? parseInt(value.trim(), 10)
|
|
45
|
+
: Number.NaN;
|
|
46
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
47
|
+
}
|
|
48
|
+
function buildRateLimitFromFormData(data) {
|
|
49
|
+
if (!Boolean(data.rateLimitEnabled)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const maxRequests = parseOptionalPositiveInteger(data.rateLimitMaxRequests);
|
|
53
|
+
const window = parseOptionalPositiveInteger(data.rateLimitWindow);
|
|
54
|
+
if (!maxRequests || !window) {
|
|
55
|
+
alert('Rate limit requires positive Max Requests and Window values.');
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
enabled: true,
|
|
60
|
+
maxRequests,
|
|
61
|
+
window,
|
|
62
|
+
keyBy: 'ip',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
40
65
|
let OpsViewSourceProfiles = (() => {
|
|
41
66
|
let _classDecorators = [customElement('ops-view-sourceprofiles')];
|
|
42
67
|
let _classDescriptor;
|
|
@@ -169,6 +194,9 @@ let OpsViewSourceProfiles = (() => {
|
|
|
169
194
|
<dees-input-list .key=${'ipAllowList'} .label=${'IP Allow List'} .placeholder=${'Add IP or CIDR...'}></dees-input-list>
|
|
170
195
|
<dees-input-list .key=${'ipBlockList'} .label=${'IP Block List'} .placeholder=${'Add IP or CIDR...'}></dees-input-list>
|
|
171
196
|
<dees-input-text .key=${'maxConnections'} .label=${'Max Connections'}></dees-input-text>
|
|
197
|
+
<dees-input-checkbox .key=${'rateLimitEnabled'} .label=${'Enable Rate Limit'} .description=${'Per source IP. Exceeded requests receive 429.'} .value=${false}></dees-input-checkbox>
|
|
198
|
+
<dees-input-text .key=${'rateLimitMaxRequests'} .label=${'Max Requests'} .description=${'Requests per source IP'}></dees-input-text>
|
|
199
|
+
<dees-input-text .key=${'rateLimitWindow'} .label=${'Window Seconds'}></dees-input-text>
|
|
172
200
|
</dees-form>
|
|
173
201
|
`,
|
|
174
202
|
menuOptions: [
|
|
@@ -182,8 +210,10 @@ let OpsViewSourceProfiles = (() => {
|
|
|
182
210
|
const data = await form.collectFormData();
|
|
183
211
|
const ipAllowList = Array.isArray(data.ipAllowList) ? data.ipAllowList : [];
|
|
184
212
|
const ipBlockList = Array.isArray(data.ipBlockList) ? data.ipBlockList : [];
|
|
185
|
-
const
|
|
186
|
-
const
|
|
213
|
+
const maxConnections = parseOptionalPositiveInteger(data.maxConnections);
|
|
214
|
+
const rateLimit = buildRateLimitFromFormData(data);
|
|
215
|
+
if (rateLimit === null)
|
|
216
|
+
return;
|
|
187
217
|
await appstate.profilesTargetsStatePart.dispatchAction(appstate.createProfileAction, {
|
|
188
218
|
name: String(data.name),
|
|
189
219
|
description: data.description ? String(data.description) : undefined,
|
|
@@ -191,6 +221,7 @@ let OpsViewSourceProfiles = (() => {
|
|
|
191
221
|
...(ipAllowList.length > 0 ? { ipAllowList } : {}),
|
|
192
222
|
...(ipBlockList.length > 0 ? { ipBlockList } : {}),
|
|
193
223
|
...(maxConnections ? { maxConnections } : {}),
|
|
224
|
+
...(rateLimit ? { rateLimit } : {}),
|
|
194
225
|
},
|
|
195
226
|
});
|
|
196
227
|
modalArg.destroy();
|
|
@@ -210,6 +241,9 @@ let OpsViewSourceProfiles = (() => {
|
|
|
210
241
|
<dees-input-list .key=${'ipAllowList'} .label=${'IP Allow List'} .placeholder=${'Add IP or CIDR...'} .value=${profile.security?.ipAllowList || []}></dees-input-list>
|
|
211
242
|
<dees-input-list .key=${'ipBlockList'} .label=${'IP Block List'} .placeholder=${'Add IP or CIDR...'} .value=${profile.security?.ipBlockList || []}></dees-input-list>
|
|
212
243
|
<dees-input-text .key=${'maxConnections'} .label=${'Max Connections'} .value=${String(profile.security?.maxConnections || '')}></dees-input-text>
|
|
244
|
+
<dees-input-checkbox .key=${'rateLimitEnabled'} .label=${'Enable Rate Limit'} .description=${'Per source IP. Exceeded requests receive 429.'} .value=${profile.security?.rateLimit?.enabled === true}></dees-input-checkbox>
|
|
245
|
+
<dees-input-text .key=${'rateLimitMaxRequests'} .label=${'Max Requests'} .description=${'Requests per source IP'} .value=${String(profile.security?.rateLimit?.maxRequests || '')}></dees-input-text>
|
|
246
|
+
<dees-input-text .key=${'rateLimitWindow'} .label=${'Window Seconds'} .value=${String(profile.security?.rateLimit?.window || '')}></dees-input-text>
|
|
213
247
|
</dees-form>
|
|
214
248
|
`,
|
|
215
249
|
menuOptions: [
|
|
@@ -223,8 +257,10 @@ let OpsViewSourceProfiles = (() => {
|
|
|
223
257
|
const data = await form.collectFormData();
|
|
224
258
|
const ipAllowList = Array.isArray(data.ipAllowList) ? data.ipAllowList : [];
|
|
225
259
|
const ipBlockList = Array.isArray(data.ipBlockList) ? data.ipBlockList : [];
|
|
226
|
-
const
|
|
227
|
-
const
|
|
260
|
+
const maxConnections = parseOptionalPositiveInteger(data.maxConnections);
|
|
261
|
+
const rateLimit = buildRateLimitFromFormData(data);
|
|
262
|
+
if (rateLimit === null)
|
|
263
|
+
return;
|
|
228
264
|
await appstate.profilesTargetsStatePart.dispatchAction(appstate.updateProfileAction, {
|
|
229
265
|
id: profile.id,
|
|
230
266
|
name: String(data.name),
|
|
@@ -233,6 +269,7 @@ let OpsViewSourceProfiles = (() => {
|
|
|
233
269
|
ipAllowList,
|
|
234
270
|
ipBlockList,
|
|
235
271
|
...(maxConnections ? { maxConnections } : {}),
|
|
272
|
+
...(rateLimit ? { rateLimit } : {}),
|
|
236
273
|
},
|
|
237
274
|
});
|
|
238
275
|
modalArg.destroy();
|
|
@@ -275,4 +312,4 @@ let OpsViewSourceProfiles = (() => {
|
|
|
275
312
|
return OpsViewSourceProfiles = _classThis;
|
|
276
313
|
})();
|
|
277
314
|
export { OpsViewSourceProfiles };
|
|
278
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BzLXZpZXctc291cmNlcHJvZmlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90c193ZWIvZWxlbWVudHMvbmV0d29yay9vcHMtdmlldy1zb3VyY2Vwcm9maWxlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsT0FBTyxFQUNMLFdBQVcsRUFDWCxJQUFJLEVBQ0osYUFBYSxFQUViLEdBQUcsRUFDSCxLQUFLLEVBQ0wsVUFBVSxHQUNYLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxLQUFLLFFBQVEsTUFBTSxtQkFBbUIsQ0FBQztBQUM5QyxPQUFPLEtBQUssVUFBVSxNQUFNLHNDQUFzQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMvQyxPQUFPLEVBQW1CLE1BQU0sNkJBQTZCLENBQUM7SUFTakQscUJBQXFCOzRCQURqQyxhQUFhLENBQUMseUJBQXlCLENBQUM7Ozs7c0JBQ0UsV0FBVzs7OztxQ0FBbkIsU0FBUSxXQUFXOzs7O3lDQUNuRCxLQUFLLEVBQUU7WUFDUiw0TEFBUyxhQUFhLDZCQUFiLGFBQWEscUdBQWlGO1lBRnpHLDZLQTZOQzs7OztRQTNOQyx1RkFBeUQsUUFBUSxDQUFDLHdCQUF3QixDQUFDLFFBQVEsRUFBRyxFQUFDO1FBQXZHLElBQVMsYUFBYSxtREFBaUY7UUFBdkcsSUFBUyxhQUFhLHlEQUFpRjtRQUV2RztZQUNFLEtBQUssRUFBRSxDQUFDOztZQUNSLE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyx3QkFBd0IsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRTtnQkFDNUUsSUFBSSxDQUFDLGFBQWEsR0FBRyxRQUFRLENBQUM7WUFDaEMsQ0FBQyxDQUFDLENBQUM7WUFDSCxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxHQUFHLENB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
|
|
315
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BzLXZpZXctc291cmNlcHJvZmlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90c193ZWIvZWxlbWVudHMvbmV0d29yay9vcHMtdmlldy1zb3VyY2Vwcm9maWxlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsT0FBTyxFQUNMLFdBQVcsRUFDWCxJQUFJLEVBQ0osYUFBYSxFQUViLEdBQUcsRUFDSCxLQUFLLEVBQ0wsVUFBVSxHQUNYLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxLQUFLLFFBQVEsTUFBTSxtQkFBbUIsQ0FBQztBQUM5QyxPQUFPLEtBQUssVUFBVSxNQUFNLHNDQUFzQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMvQyxPQUFPLEVBQW1CLE1BQU0sNkJBQTZCLENBQUM7QUFFOUQsU0FBUyw0QkFBNEIsQ0FBQyxLQUFjO0lBQ2xELE1BQU0sTUFBTSxHQUFHLE9BQU8sS0FBSyxLQUFLLFFBQVE7UUFDdEMsQ0FBQyxDQUFDLEtBQUs7UUFDUCxDQUFDLENBQUMsT0FBTyxLQUFLLEtBQUssUUFBUTtZQUN6QixDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUM7WUFDNUIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7SUFDakIsT0FBTyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQ3JFLENBQUM7QUFFRCxTQUFTLDBCQUEwQixDQUFDLElBQXlCO0lBQzNELElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQztRQUNwQyxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFD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
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serve.zone/dcrouter",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "13.
|
|
4
|
+
"version": "13.42.0",
|
|
5
5
|
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@git.zone/tsbuild": "^4.4.2",
|
|
19
19
|
"@git.zone/tsbundle": "^2.10.4",
|
|
20
|
-
"@git.zone/tsdocker": "^2.4.0",
|
|
21
20
|
"@git.zone/tsdeno": "^1.5.0",
|
|
21
|
+
"@git.zone/tsdocker": "^2.4.0",
|
|
22
22
|
"@git.zone/tsrun": "^2.0.4",
|
|
23
23
|
"@git.zone/tstest": "^3.6.6",
|
|
24
24
|
"@git.zone/tswatch": "^3.3.5",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@push.rocks/smartnetwork": "^4.7.2",
|
|
51
51
|
"@push.rocks/smartpath": "^6.0.0",
|
|
52
52
|
"@push.rocks/smartpromise": "^4.2.4",
|
|
53
|
-
"@push.rocks/smartproxy": "^27.12.
|
|
53
|
+
"@push.rocks/smartproxy": "^27.12.4",
|
|
54
54
|
"@push.rocks/smartradius": "^1.3.0",
|
|
55
55
|
"@push.rocks/smartrequest": "^5.0.3",
|
|
56
56
|
"@push.rocks/smartrx": "^3.0.10",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"@push.rocks/taskbuffer": "^8.0.2",
|
|
61
61
|
"@serve.zone/catalog": "^2.12.4",
|
|
62
62
|
"@serve.zone/interfaces": "^5.8.0",
|
|
63
|
-
"@serve.zone/remoteingress": "^4.22.
|
|
63
|
+
"@serve.zone/remoteingress": "^4.22.4",
|
|
64
64
|
"@tsclass/tsclass": "^9.5.1",
|
|
65
65
|
"@types/qrcode": "^1.5.6",
|
|
66
66
|
"lru-cache": "^11.4.0",
|
package/readme.md
CHANGED
|
@@ -146,6 +146,80 @@ dcrouter keeps generated and operator-created routes separate so automation can
|
|
|
146
146
|
|
|
147
147
|
System routes are persisted with stable `systemKey` values. API-created routes are the editable route layer intended for operators and automation.
|
|
148
148
|
|
|
149
|
+
## Route Source Policies
|
|
150
|
+
|
|
151
|
+
API-created route records pass `metadata.sourcePolicy` alongside the SmartProxy route config to express ordered source and path policy variants without duplicating whole routes by hand. A source policy contains ordered `bindings`, each pointing at a source profile id through `sourceProfileRef`. Dashboard presets resolve seeded profile names to ids before saving.
|
|
152
|
+
|
|
153
|
+
Runtime behavior:
|
|
154
|
+
|
|
155
|
+
- Source matching uses the referenced `SourceProfile.security.ipAllowList`.
|
|
156
|
+
- Bindings are evaluated in order and the first matching source profile wins.
|
|
157
|
+
- A matched binding that exceeds its configured rate or connection limit is terminal and returns `429`; dcrouter does not fall through to later bindings.
|
|
158
|
+
- Source-policy rate limits are always keyed by source IP; dcrouter ignores `path` and `header` keying on source-policy binding and path-policy overrides.
|
|
159
|
+
- A public fallback binding must be last and must use `*`, or both `0.0.0.0/0` and `::/0`, in `security.ipAllowList`.
|
|
160
|
+
- Create/update paths reject source policies with missing source profiles, source profiles without source matches, missing final all-source fallback, or any all-source binding that shadows later bindings; persisted invalid policies fail closed at compile time.
|
|
161
|
+
- Server-side caps bound policy expansion to 16 source bindings, 12 path policies per binding, 64 path patterns per path policy, 256 characters and 8 wildcards per custom path pattern, and 512 compiled SmartProxy route-port variants per stored route.
|
|
162
|
+
|
|
163
|
+
Path policies let a source binding override rate limits or connection limits for specific path classes. dcrouter currently ships Gitea-oriented classes: `git-smart-http`, `static`, `normal-html`, `expensive-html`, `raw`, and `archive`. Path-specific variants win over the same binding's fallback; if every path policy is path-specific, dcrouter adds a source-level fallback route for unmatched paths so normal browsing cannot fall through to a later source binding. The Gitea preset keeps `git-smart-http` high-limit and separate from HTML crawling paths so normal `git clone`, `git fetch`, `git push`, and Git LFS traffic are not subject to the lower HTML crawler limits.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const trustedProfileId = 'source-profile-id-trusted';
|
|
167
|
+
const publicProfileId = 'source-profile-id-public';
|
|
168
|
+
|
|
169
|
+
const createRoutePayload = {
|
|
170
|
+
route: {
|
|
171
|
+
name: 'public-gitea',
|
|
172
|
+
match: { domains: ['code.example.com'], ports: [443] },
|
|
173
|
+
action: {
|
|
174
|
+
type: 'forward',
|
|
175
|
+
targets: [{ host: '10.10.0.20', port: 3000 }],
|
|
176
|
+
tls: { mode: 'terminate', certificate: 'auto' },
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
metadata: {
|
|
180
|
+
sourcePolicy: {
|
|
181
|
+
bindings: [
|
|
182
|
+
{
|
|
183
|
+
sourceProfileRef: trustedProfileId,
|
|
184
|
+
maxConnections: 5000,
|
|
185
|
+
onExceeded: { type: '429' },
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
sourceProfileRef: publicProfileId,
|
|
189
|
+
onExceeded: { type: '429' },
|
|
190
|
+
pathPolicies: [
|
|
191
|
+
{
|
|
192
|
+
pathClass: 'git-smart-http',
|
|
193
|
+
rateLimit: { enabled: true, maxRequests: 1200, window: 60, keyBy: 'ip' },
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
pathClass: 'static',
|
|
197
|
+
rateLimit: { enabled: true, maxRequests: 600, window: 60, keyBy: 'ip' },
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
pathClass: 'raw',
|
|
201
|
+
rateLimit: { enabled: true, maxRequests: 120, window: 60, keyBy: 'ip' },
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
pathClass: 'archive',
|
|
205
|
+
rateLimit: { enabled: true, maxRequests: 30, window: 60, keyBy: 'ip' },
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
pathClass: 'expensive-html',
|
|
209
|
+
rateLimit: { enabled: true, maxRequests: 30, window: 60, keyBy: 'ip' },
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
pathClass: 'normal-html',
|
|
213
|
+
rateLimit: { enabled: true, maxRequests: 120, window: 60, keyBy: 'ip' },
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
```
|
|
222
|
+
|
|
149
223
|
## Production-Flavored Example
|
|
150
224
|
|
|
151
225
|
```typescript
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -68,11 +68,38 @@ export class DbSeeder {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const DEFAULT_PROFILES: Array<NonNullable<ISeedData['profiles']>[number]> = [
|
|
71
|
+
{
|
|
72
|
+
name: 'TRUSTED NETWORKS',
|
|
73
|
+
description: 'Trusted office, VPN, localhost, and private-network sources with high connection allowance',
|
|
74
|
+
security: {
|
|
75
|
+
ipAllowList: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '127.0.0.1', '::1'],
|
|
76
|
+
maxConnections: 5000,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'AI CRAWLERS',
|
|
81
|
+
description: 'Add verified crawler CIDRs before assigning this profile in a source policy',
|
|
82
|
+
security: {
|
|
83
|
+
ipAllowList: [],
|
|
84
|
+
rateLimit: {
|
|
85
|
+
enabled: true,
|
|
86
|
+
maxRequests: 30,
|
|
87
|
+
window: 60,
|
|
88
|
+
keyBy: 'ip',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
71
92
|
{
|
|
72
93
|
name: 'PUBLIC',
|
|
73
|
-
description: '
|
|
94
|
+
description: 'Public fallback source profile with per-IP request limiting',
|
|
74
95
|
security: {
|
|
75
96
|
ipAllowList: ['*'],
|
|
97
|
+
rateLimit: {
|
|
98
|
+
enabled: true,
|
|
99
|
+
maxRequests: 120,
|
|
100
|
+
window: 60,
|
|
101
|
+
keyBy: 'ip',
|
|
102
|
+
},
|
|
76
103
|
},
|
|
77
104
|
},
|
|
78
105
|
{
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
IRouteMetadata,
|
|
8
8
|
IRoute,
|
|
9
9
|
IRouteSecurity,
|
|
10
|
+
IRouteSourcePolicy,
|
|
10
11
|
} from '../../ts_interfaces/data/route-management.js';
|
|
11
12
|
|
|
12
13
|
const MAX_INHERITANCE_DEPTH = 5;
|
|
@@ -107,7 +108,7 @@ export class ReferenceResolver {
|
|
|
107
108
|
|
|
108
109
|
// If force-deleting with referencing routes, clear refs but keep resolved values
|
|
109
110
|
if (affectedIds.length > 0) {
|
|
110
|
-
await this.clearProfileRefsOnRoutes(affectedIds);
|
|
111
|
+
await this.clearProfileRefsOnRoutes(id, affectedIds, storedRoutes);
|
|
111
112
|
logger.log('warn', `Force-deleted profile '${profile.name}'; cleared refs on ${affectedIds.length} route(s)`);
|
|
112
113
|
} else {
|
|
113
114
|
logger.log('info', `Deleted source profile '${profile.name}' (${id})`);
|
|
@@ -131,15 +132,22 @@ export class ReferenceResolver {
|
|
|
131
132
|
return [...this.profiles.values()];
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
public resolveSourceProfileSecurity(profileId: string): IRouteSecurity | null {
|
|
136
|
+
const resolvedSecurity = this.resolveSourceProfile(profileId);
|
|
137
|
+
return resolvedSecurity ? this.cloneSecurityFields(resolvedSecurity) : null;
|
|
138
|
+
}
|
|
139
|
+
|
|
134
140
|
public getProfileUsage(storedRoutes: Map<string, IRoute>): Map<string, Array<{ id: string; routeName: string }>> {
|
|
135
141
|
const usage = new Map<string, Array<{ id: string; routeName: string }>>();
|
|
136
142
|
for (const profile of this.profiles.values()) {
|
|
137
143
|
usage.set(profile.id, []);
|
|
138
144
|
}
|
|
139
145
|
for (const [routeId, stored] of storedRoutes) {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
usage.
|
|
146
|
+
const refs = this.getSourceProfileRefsFromMetadata(stored.metadata);
|
|
147
|
+
for (const ref of refs) {
|
|
148
|
+
if (usage.has(ref)) {
|
|
149
|
+
usage.get(ref)!.push({ id: routeId, routeName: stored.route.name || routeId });
|
|
150
|
+
}
|
|
143
151
|
}
|
|
144
152
|
}
|
|
145
153
|
return usage;
|
|
@@ -151,7 +159,7 @@ export class ReferenceResolver {
|
|
|
151
159
|
): Array<{ id: string; routeName: string }> {
|
|
152
160
|
const routes: Array<{ id: string; routeName: string }> = [];
|
|
153
161
|
for (const [routeId, stored] of storedRoutes) {
|
|
154
|
-
if (stored.metadata
|
|
162
|
+
if (this.metadataUsesSourceProfile(stored.metadata, profileId)) {
|
|
155
163
|
routes.push({ id: routeId, routeName: stored.route.name || routeId });
|
|
156
164
|
}
|
|
157
165
|
}
|
|
@@ -290,7 +298,15 @@ export class ReferenceResolver {
|
|
|
290
298
|
): { route: plugins.smartproxy.IRouteConfig; metadata: IRouteMetadata } {
|
|
291
299
|
const resolvedMetadata: IRouteMetadata = { ...metadata };
|
|
292
300
|
|
|
293
|
-
if (resolvedMetadata.
|
|
301
|
+
if (resolvedMetadata.sourcePolicy?.bindings.length) {
|
|
302
|
+
const resolvedSourcePolicy = this.resolveRouteSourcePolicy(resolvedMetadata.sourcePolicy);
|
|
303
|
+
if (resolvedSourcePolicy) {
|
|
304
|
+
resolvedMetadata.sourcePolicy = resolvedSourcePolicy;
|
|
305
|
+
resolvedMetadata.sourceProfileRef = undefined;
|
|
306
|
+
resolvedMetadata.sourceProfileName = undefined;
|
|
307
|
+
resolvedMetadata.lastResolvedAt = Date.now();
|
|
308
|
+
}
|
|
309
|
+
} else if (resolvedMetadata.sourceProfileRef) {
|
|
294
310
|
const resolvedSecurity = this.resolveSourceProfile(resolvedMetadata.sourceProfileRef);
|
|
295
311
|
if (resolvedSecurity) {
|
|
296
312
|
const profile = this.profiles.get(resolvedMetadata.sourceProfileRef);
|
|
@@ -336,7 +352,7 @@ export class ReferenceResolver {
|
|
|
336
352
|
public async findRoutesByProfileRef(profileId: string): Promise<string[]> {
|
|
337
353
|
const docs = await RouteDoc.findAll();
|
|
338
354
|
return docs
|
|
339
|
-
.filter((doc) => doc.metadata
|
|
355
|
+
.filter((doc) => this.metadataUsesSourceProfile(doc.metadata, profileId))
|
|
340
356
|
.map((doc) => doc.id);
|
|
341
357
|
}
|
|
342
358
|
|
|
@@ -350,7 +366,7 @@ export class ReferenceResolver {
|
|
|
350
366
|
public findRoutesByProfileRefSync(profileId: string, storedRoutes: Map<string, IRoute>): string[] {
|
|
351
367
|
const ids: string[] = [];
|
|
352
368
|
for (const [routeId, stored] of storedRoutes) {
|
|
353
|
-
if (stored.metadata
|
|
369
|
+
if (this.metadataUsesSourceProfile(stored.metadata, profileId)) {
|
|
354
370
|
ids.push(routeId);
|
|
355
371
|
}
|
|
356
372
|
}
|
|
@@ -371,6 +387,41 @@ export class ReferenceResolver {
|
|
|
371
387
|
// Private: source profile resolution with inheritance
|
|
372
388
|
// =========================================================================
|
|
373
389
|
|
|
390
|
+
private resolveRouteSourcePolicy(sourcePolicy: IRouteSourcePolicy): IRouteSourcePolicy | undefined {
|
|
391
|
+
const bindings = sourcePolicy.bindings
|
|
392
|
+
.map((binding) => {
|
|
393
|
+
const profile = this.profiles.get(binding.sourceProfileRef);
|
|
394
|
+
if (!profile) {
|
|
395
|
+
logger.log('warn', `Source profile '${binding.sourceProfileRef}' not found during source policy resolution`);
|
|
396
|
+
return binding;
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
...binding,
|
|
400
|
+
sourceProfileName: profile.name,
|
|
401
|
+
};
|
|
402
|
+
})
|
|
403
|
+
.filter((binding) => binding.sourceProfileRef);
|
|
404
|
+
|
|
405
|
+
return bindings.length > 0 ? { bindings } : undefined;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
private metadataUsesSourceProfile(metadata: IRouteMetadata | undefined, profileId: string): boolean {
|
|
409
|
+
return this.getSourceProfileRefsFromMetadata(metadata).includes(profileId);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private getSourceProfileRefsFromMetadata(metadata: IRouteMetadata | undefined): string[] {
|
|
413
|
+
const refs = new Set<string>();
|
|
414
|
+
if (metadata?.sourceProfileRef) {
|
|
415
|
+
refs.add(metadata.sourceProfileRef);
|
|
416
|
+
}
|
|
417
|
+
for (const binding of metadata?.sourcePolicy?.bindings || []) {
|
|
418
|
+
if (binding.sourceProfileRef) {
|
|
419
|
+
refs.add(binding.sourceProfileRef);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return [...refs];
|
|
423
|
+
}
|
|
424
|
+
|
|
374
425
|
private resolveSourceProfile(
|
|
375
426
|
profileId: string,
|
|
376
427
|
visited: Set<string> = new Set(),
|
|
@@ -550,21 +601,50 @@ export class ReferenceResolver {
|
|
|
550
601
|
// Private: ref cleanup on force-delete
|
|
551
602
|
// =========================================================================
|
|
552
603
|
|
|
553
|
-
private async clearProfileRefsOnRoutes(
|
|
604
|
+
private async clearProfileRefsOnRoutes(
|
|
605
|
+
profileId: string,
|
|
606
|
+
routeIds: string[],
|
|
607
|
+
storedRoutes?: Map<string, IRoute>,
|
|
608
|
+
): Promise<void> {
|
|
554
609
|
for (const routeId of routeIds) {
|
|
555
610
|
const doc = await RouteDoc.findById(routeId);
|
|
556
611
|
if (doc?.metadata) {
|
|
557
|
-
doc.metadata =
|
|
558
|
-
...doc.metadata,
|
|
559
|
-
sourceProfileRef: undefined,
|
|
560
|
-
sourceProfileName: undefined,
|
|
561
|
-
};
|
|
612
|
+
doc.metadata = this.clearSourceProfileFromMetadata(doc.metadata, profileId);
|
|
562
613
|
doc.updatedAt = Date.now();
|
|
563
614
|
await doc.save();
|
|
564
615
|
}
|
|
616
|
+
|
|
617
|
+
const storedRoute = storedRoutes?.get(routeId);
|
|
618
|
+
if (storedRoute?.metadata) {
|
|
619
|
+
storedRoute.metadata = this.clearSourceProfileFromMetadata(storedRoute.metadata, profileId);
|
|
620
|
+
storedRoute.updatedAt = Date.now();
|
|
621
|
+
}
|
|
565
622
|
}
|
|
566
623
|
}
|
|
567
624
|
|
|
625
|
+
private clearSourceProfileFromMetadata(metadata: IRouteMetadata, profileId: string): IRouteMetadata {
|
|
626
|
+
const sourcePolicy = metadata.sourcePolicy?.bindings?.length
|
|
627
|
+
? {
|
|
628
|
+
bindings: metadata.sourcePolicy.bindings.filter(
|
|
629
|
+
(binding) => binding.sourceProfileRef !== profileId,
|
|
630
|
+
),
|
|
631
|
+
}
|
|
632
|
+
: undefined;
|
|
633
|
+
|
|
634
|
+
const nextMetadata: IRouteMetadata = {
|
|
635
|
+
...metadata,
|
|
636
|
+
sourceProfileRef: metadata.sourceProfileRef === profileId ? undefined : metadata.sourceProfileRef,
|
|
637
|
+
sourceProfileName: metadata.sourceProfileRef === profileId ? undefined : metadata.sourceProfileName,
|
|
638
|
+
sourcePolicy: sourcePolicy?.bindings.length ? sourcePolicy : undefined,
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
if (!nextMetadata.sourceProfileRef && !nextMetadata.sourcePolicy && !nextMetadata.networkTargetRef) {
|
|
642
|
+
nextMetadata.lastResolvedAt = undefined;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return nextMetadata;
|
|
646
|
+
}
|
|
647
|
+
|
|
568
648
|
private async clearTargetRefsOnRoutes(routeIds: string[]): Promise<void> {
|
|
569
649
|
for (const routeId of routeIds) {
|
|
570
650
|
const doc = await RouteDoc.findById(routeId);
|