@serve.zone/dcrouter 17.8.0 → 17.9.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.
Files changed (29) hide show
  1. package/deno.json +1 -1
  2. package/dist_serve/bundle.js +373 -370
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/config/classes.db-seeder.js +9 -1
  5. package/dist_ts/config/helpers.http-redirects.js +28 -1
  6. package/dist_ts/config/helpers.special-forwards.js +12 -9
  7. package/dist_ts/email/classes.email-route-builder.js +5 -1
  8. package/dist_ts/opsserver/handlers/gatewayclient.handler.js +23 -2
  9. package/dist_ts/remoteingress/edge-derivation-routes.js +5 -1
  10. package/dist_ts/security/classes.route-policy-augmenter.d.ts +10 -6
  11. package/dist_ts/security/classes.route-policy-augmenter.js +65 -51
  12. package/dist_ts_interfaces/data/remoteingress.d.ts +14 -2
  13. package/dist_ts_migrations/index.js +66 -2
  14. package/dist_ts_web/00_commitinfo_data.js +1 -1
  15. package/dist_ts_web/elements/network/ops-view-routes.js +41 -1
  16. package/dist_ts_web/elements/network/special-forward-dialog.js +2 -2
  17. package/package.json +4 -4
  18. package/readme.plan.md +22 -0
  19. package/ts/00_commitinfo_data.ts +1 -1
  20. package/ts/config/classes.db-seeder.ts +8 -0
  21. package/ts/config/helpers.http-redirects.ts +31 -1
  22. package/ts/config/helpers.special-forwards.ts +11 -8
  23. package/ts/email/classes.email-route-builder.ts +4 -0
  24. package/ts/opsserver/handlers/gatewayclient.handler.ts +24 -1
  25. package/ts/remoteingress/edge-derivation-routes.ts +4 -0
  26. package/ts/security/classes.route-policy-augmenter.ts +70 -57
  27. package/ts_web/00_commitinfo_data.ts +1 -1
  28. package/ts_web/elements/network/ops-view-routes.ts +38 -0
  29. package/ts_web/elements/network/special-forward-dialog.ts +1 -1
@@ -1,8 +1,8 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  /**
3
3
  * Pure route-policy transformations applied before routes reach SmartProxy:
4
- * per-listener inbound PROXY protocol policies (driven by RemoteIngress and
5
- * VPN) and merging of compiled security policies.
4
+ * route-level trusted ingress authorization, listener-level inbound PROXY
5
+ * protocol policy, and merging of compiled security policies.
6
6
  */
7
7
  export class RoutePolicyAugmenter {
8
8
  dcRouterRef;
@@ -10,42 +10,53 @@ export class RoutePolicyAugmenter {
10
10
  this.dcRouterRef = dcRouterRef;
11
11
  }
12
12
  /**
13
- * Ensure every route on a shared listener carries a compatible
14
- * inboundProxyProtocol policy, deriving defaults from RemoteIngress/VPN.
13
+ * Compile each dcrouter ingress policy into SmartProxy route security, then
14
+ * derive one compatible PROXY protocol mode for every shared listener.
15
+ *
16
+ * The listener mode only controls parsing. Route security remains the
17
+ * authorization boundary, so a direct request cannot fall through to a
18
+ * wildcard route that only permits RemoteIngress or SmartVPN.
15
19
  */
16
20
  applyInboundProxyProtocolPolicies(routes) {
17
- const policiesByListener = new Map();
18
- for (const route of routes) {
19
- const policy = route.match?.inboundProxyProtocol || this.getDesiredInboundProxyProtocolPolicy(route);
20
- if (!policy) {
21
- continue;
21
+ const routesWithIngressSecurity = routes.map((route) => {
22
+ const allowedOrigins = this.getAllowedIngressOrigins(route);
23
+ if (allowedOrigins.length === 0) {
24
+ throw new Error(`Route '${route.name}' has no enabled ingress path`);
22
25
  }
26
+ return {
27
+ ...route,
28
+ security: {
29
+ ...route.security,
30
+ ingress: {
31
+ allowedOrigins,
32
+ },
33
+ },
34
+ };
35
+ });
36
+ const originsByListener = new Map();
37
+ for (const route of routesWithIngressSecurity) {
38
+ const origins = route.security.ingress.allowedOrigins;
23
39
  for (const listenerKey of this.getInboundProxyListenerKeys(route)) {
24
- const mergedPolicy = this.mergeInboundProxyProtocolPolicies(policiesByListener.get(listenerKey), policy);
25
- if (mergedPolicy) {
26
- policiesByListener.set(listenerKey, mergedPolicy);
40
+ const listenerOrigins = originsByListener.get(listenerKey) || new Set();
41
+ for (const origin of origins) {
42
+ listenerOrigins.add(origin);
27
43
  }
44
+ originsByListener.set(listenerKey, listenerOrigins);
28
45
  }
29
46
  }
30
- if (policiesByListener.size === 0) {
31
- return routes;
32
- }
33
- return routes.map((route) => {
34
- if (route.match?.inboundProxyProtocol) {
35
- return route;
36
- }
37
- let listenerPolicy;
47
+ return routesWithIngressSecurity.map((route) => {
48
+ const listenerOrigins = new Set();
38
49
  for (const listenerKey of this.getInboundProxyListenerKeys(route)) {
39
- listenerPolicy = this.mergeInboundProxyProtocolPolicies(listenerPolicy, policiesByListener.get(listenerKey));
40
- }
41
- if (!listenerPolicy) {
42
- return route;
50
+ for (const origin of originsByListener.get(listenerKey) || []) {
51
+ listenerOrigins.add(origin);
52
+ }
43
53
  }
54
+ const inboundProxyProtocol = this.getListenerProxyProtocolPolicy(listenerOrigins);
44
55
  return {
45
56
  ...route,
46
57
  match: {
47
58
  ...route.match,
48
- inboundProxyProtocol: listenerPolicy,
59
+ inboundProxyProtocol,
49
60
  },
50
61
  };
51
62
  });
@@ -72,19 +83,37 @@ export class RoutePolicyAugmenter {
72
83
  blockedCidrs: [...blockedCidrs].sort(),
73
84
  };
74
85
  }
75
- getDesiredInboundProxyProtocolPolicy(route) {
86
+ getAllowedIngressOrigins(route) {
76
87
  const dcRoute = route;
77
- if (this.dcRouterRef.isRemoteIngressHubEnabled() && dcRoute.remoteIngress?.enabled) {
78
- const ports = plugins.smartproxy.expandPortRange(route.match.ports);
79
- if (ports.some((port) => port === 25 || port === 587)) {
80
- return { mode: 'required' };
81
- }
82
- return { mode: 'optional' };
88
+ const origins = new Set();
89
+ if (dcRoute.ingress) {
90
+ if (dcRoute.ingress.directHub)
91
+ origins.add('direct');
92
+ if (dcRoute.ingress.smartVpn)
93
+ origins.add('smartVpn');
83
94
  }
84
- if (this.dcRouterRef.options.vpnConfig?.enabled) {
85
- return { mode: 'optional' };
95
+ else if (dcRoute.vpnOnly) {
96
+ origins.add('smartVpn');
97
+ }
98
+ else {
99
+ // Compatibility for runtime routes and producers predating the explicit
100
+ // contract. Persisted routes are backfilled by the versioned migration.
101
+ origins.add('direct');
102
+ origins.add('smartVpn');
86
103
  }
87
- return undefined;
104
+ if (dcRoute.remoteIngress?.enabled) {
105
+ origins.add('trustedProxy');
106
+ }
107
+ return [...origins];
108
+ }
109
+ getListenerProxyProtocolPolicy(origins) {
110
+ const allowsDirect = origins.has('direct');
111
+ const allowsProxied = origins.has('trustedProxy') || origins.has('smartVpn');
112
+ if (allowsDirect && allowsProxied)
113
+ return { mode: 'optional' };
114
+ if (allowsProxied)
115
+ return { mode: 'required' };
116
+ return { mode: 'reject' };
88
117
  }
89
118
  getInboundProxyListenerKeys(route) {
90
119
  const ports = plugins.smartproxy.expandPortRange(route.match.ports);
@@ -101,20 +130,5 @@ export class RoutePolicyAugmenter {
101
130
  }
102
131
  return keys;
103
132
  }
104
- mergeInboundProxyProtocolPolicies(current, next) {
105
- if (!current)
106
- return next;
107
- if (!next)
108
- return current;
109
- if (current.mode === 'required')
110
- return current;
111
- if (next.mode === 'required')
112
- return next;
113
- if (current.mode === 'optional')
114
- return current;
115
- if (next.mode === 'optional')
116
- return next;
117
- return current;
118
- }
119
133
  }
120
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5yb3V0ZS1wb2xpY3ktYXVnbWVudGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvc2VjdXJpdHkvY2xhc3Nlcy5yb3V0ZS1wb2xpY3ktYXVnbWVudGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBT3pDOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sb0JBQW9CO0lBQ1g7SUFBcEIsWUFBb0IsV0FBcUI7UUFBckIsZ0JBQVcsR0FBWCxXQUFXLENBQVU7SUFBRyxDQUFDO0lBRTdDOzs7T0FHRztJQUNJLGlDQUFpQyxDQUN0QyxNQUF5QztRQUV6QyxNQUFNLGtCQUFrQixHQUFHLElBQUksR0FBRyxFQUF1QyxDQUFDO1FBRTFFLEtBQUssTUFBTSxLQUFLLElBQUksTUFBTSxFQUFFLENBQUM7WUFDM0IsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLEtBQUssRUFBRSxvQkFBb0IsSUFBSSxJQUFJLENBQUMsb0NBQW9DLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDckcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNaLFNBQVM7WUFDWCxDQUFDO1lBQ0QsS0FBSyxNQUFNLFdBQVcsSUFBSSxJQUFJLENBQUMsMkJBQTJCLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDbEUsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGlDQUFpQyxDQUN6RCxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQ25DLE1BQU0sQ0FDUCxDQUFDO2dCQUNGLElBQUksWUFBWSxFQUFFLENBQUM7b0JBQ2pCLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsWUFBWSxDQUFDLENBQUM7Z0JBQ3BELENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksa0JBQWtCLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2xDLE9BQU8sTUFBTSxD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
134
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5yb3V0ZS1wb2xpY3ktYXVnbWVudGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvc2VjdXJpdHkvY2xhc3Nlcy5yb3V0ZS1wb2xpY3ktYXVnbWVudGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBVXpDOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sb0JBQW9CO0lBQ1g7SUFBcEIsWUFBb0IsV0FBcUI7UUFBckIsZ0JBQVcsR0FBWCxXQUFXLENBQVU7SUFBRyxDQUFDO0lBRTdDOzs7Ozs7O09BT0c7SUFDSSxpQ0FBaUMsQ0FDdEMsTUFBeUM7UUFFekMsTUFBTSx5QkFBeUIsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDckQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzVELElBQUksY0FBYyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDaEMsTUFBTSxJQUFJLEtBQUssQ0FBQyxVQUFVLEtBQUssQ0FBQyxJQUFJLCtCQUErQixDQUFDLENBQUM7WUFDdkUsQ0FBQztZQUNELE9BQU87Z0JBQ0wsR0FBRyxLQUFLO2dCQUNSLFFBQVEsRUFBRTtvQkFDUixHQUFHLEtBQUssQ0FBQyxRQUFRO29CQUNqQixPQUFPLEVBQUU7d0JBQ1AsY0FBYztxQkFDZjtpQkFDRjthQUNGLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztRQUVILE1BQU0saUJBQWlCLEdBQUcsSUFBSSxHQUFHLEVBQStCLENBQUM7UUFDakUsS0FBSyxNQUFNLEtBQUssSUFBSSx5QkFBeUIsRUFBRSxDQUFDO1lBQzlDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxRQUFTLENBQUMsT0FBUSxDQUFDLGNBQWMsQ0FBQztZQUN4RCxLQUFLLE1BQU0sV0FBVyxJQUFJLElBQUksQ0FBQywy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
@@ -148,14 +148,26 @@ export interface IRouteRemoteIngress {
148
148
  * When absent, the route applies to all edges. */
149
149
  edgeFilter?: string[];
150
150
  }
151
+ export interface IRouteIngress {
152
+ /** Accept traffic connected directly to the gateway hub listener. */
153
+ directHub: boolean;
154
+ /** Accept authenticated SmartVPN traffic carrying trusted VPN metadata. */
155
+ smartVpn: boolean;
156
+ }
151
157
  /**
152
158
  * Extended route config used within dcrouter.
153
- * Adds optional `remoteIngress` and `vpnOnly` properties to SmartProxy's IRouteConfig.
159
+ * Adds explicit ingress path policy and dcrouter compatibility properties to
160
+ * SmartProxy's IRouteConfig.
154
161
  * SmartProxy ignores unknown properties at runtime.
155
162
  */
156
163
  export type IDcRouterRouteConfig = IRouteConfig & {
164
+ /**
165
+ * Explicit trusted ingress paths. New routes must opt in; direct hub
166
+ * listening is intentionally not a default.
167
+ */
168
+ ingress?: IRouteIngress;
157
169
  remoteIngress?: IRouteRemoteIngress;
158
- /** When true, only VPN clients whose TargetProfile matches this route get access.
170
+ /** Compatibility policy: only VPN clients whose TargetProfile matches this route get access.
159
171
  * Matching is determined by domain overlap, target overlap, or direct routeRef. */
160
172
  vpnOnly?: boolean;
161
173
  };