@serve.zone/dcrouter 16.2.1 → 16.3.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 +1 -1
- package/dist_serve/bundle.js +1024 -960
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/config/helpers.http-redirects.d.ts +1 -1
- package/dist_ts/config/helpers.http-redirects.js +4 -3
- package/dist_ts_interfaces/data/route-management.d.ts +2 -0
- package/dist_ts_interfaces/data/route-management.js +6 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/access/ops-view-apitokens.js +3 -3
- package/dist_ts_web/elements/access/ops-view-gatewayclients.js +3 -3
- package/dist_ts_web/elements/network/ops-view-network-activity.js +6 -6
- package/dist_ts_web/elements/network/ops-view-redirects.d.ts +2 -0
- package/dist_ts_web/elements/network/ops-view-redirects.js +14 -3
- package/dist_ts_web/elements/network/ops-view-remoteingress.js +3 -3
- package/dist_ts_web/elements/network/ops-view-routes.d.ts +6 -7
- package/dist_ts_web/elements/network/ops-view-routes.js +178 -132
- package/dist_ts_web/elements/network/ops-view-special-forwards.d.ts +2 -0
- package/dist_ts_web/elements/network/ops-view-special-forwards.js +38 -10
- package/dist_ts_web/elements/network/ops-view-vpn.js +3 -3
- package/dist_ts_web/elements/network/route-view-filters.d.ts +6 -0
- package/dist_ts_web/elements/network/route-view-filters.js +29 -0
- package/dist_ts_web/elements/security/ops-view-security-blocked.js +6 -6
- package/package.json +2 -2
- package/readme.md +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/config/helpers.http-redirects.ts +6 -3
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/access/ops-view-apitokens.ts +2 -2
- package/ts_web/elements/access/ops-view-gatewayclients.ts +2 -2
- package/ts_web/elements/network/ops-view-network-activity.ts +5 -5
- package/ts_web/elements/network/ops-view-redirects.ts +9 -1
- package/ts_web/elements/network/ops-view-remoteingress.ts +2 -2
- package/ts_web/elements/network/ops-view-routes.ts +197 -138
- package/ts_web/elements/network/ops-view-special-forwards.ts +35 -7
- package/ts_web/elements/network/ops-view-vpn.ts +2 -2
- package/ts_web/elements/network/route-view-filters.ts +43 -0
- package/ts_web/elements/security/ops-view-security-blocked.ts +5 -5
- package/ts_web/readme.md +4 -4
|
@@ -4,12 +4,18 @@ import {
|
|
|
4
4
|
cssManager,
|
|
5
5
|
customElement,
|
|
6
6
|
html,
|
|
7
|
+
property,
|
|
7
8
|
state,
|
|
8
9
|
type TemplateResult,
|
|
9
10
|
} from '@design.estate/dees-element';
|
|
10
11
|
import * as appstate from '../../appstate.js';
|
|
11
12
|
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
12
13
|
import { viewHostCss } from '../shared/css.js';
|
|
14
|
+
import {
|
|
15
|
+
getRouteOwner,
|
|
16
|
+
routeMatchesOwner,
|
|
17
|
+
type TRouteOwnerFilter,
|
|
18
|
+
} from './route-view-filters.js';
|
|
13
19
|
|
|
14
20
|
const managedRouteKind = 'letsencrypt-http01-forward' as const;
|
|
15
21
|
|
|
@@ -40,6 +46,9 @@ function getTarget(route: interfaces.data.IMergedRoute): { host: string; port: n
|
|
|
40
46
|
|
|
41
47
|
@customElement('ops-view-special-forwards')
|
|
42
48
|
export class OpsViewSpecialForwards extends DeesElement {
|
|
49
|
+
@property({ type: String })
|
|
50
|
+
accessor ownerFilter: TRouteOwnerFilter = 'all';
|
|
51
|
+
|
|
43
52
|
@state()
|
|
44
53
|
accessor routeState: appstate.IRouteManagementState = appstate.routeManagementStatePart.getState()!;
|
|
45
54
|
|
|
@@ -98,7 +107,7 @@ export class OpsViewSpecialForwards extends DeesElement {
|
|
|
98
107
|
public render(): TemplateResult {
|
|
99
108
|
const forwards = this.routeState.mergedRoutes.filter((route) => {
|
|
100
109
|
return route.metadata?.managedRouteKind === managedRouteKind
|
|
101
|
-
&& route.
|
|
110
|
+
&& routeMatchesOwner(route, this.ownerFilter);
|
|
102
111
|
});
|
|
103
112
|
|
|
104
113
|
return html`
|
|
@@ -120,9 +129,15 @@ export class OpsViewSpecialForwards extends DeesElement {
|
|
|
120
129
|
.showColumnFilters=${true}
|
|
121
130
|
.displayFunction=${(route: interfaces.data.IMergedRoute) => {
|
|
122
131
|
const target = getTarget(route);
|
|
132
|
+
const owner = getRouteOwner(route);
|
|
123
133
|
return {
|
|
124
134
|
Status: route.enabled ? 'Enabled' : 'Disabled',
|
|
125
135
|
Type: 'Let\'s Encrypt HTTP-01',
|
|
136
|
+
Owner: owner === 'operator'
|
|
137
|
+
? 'User'
|
|
138
|
+
: owner === 'gatewayClient'
|
|
139
|
+
? 'Gateway Client'
|
|
140
|
+
: 'System',
|
|
126
141
|
Name: route.route.name || route.id,
|
|
127
142
|
Domains: getDomains(route).join(', '),
|
|
128
143
|
Path: route.route.match.path || '-',
|
|
@@ -132,12 +147,16 @@ export class OpsViewSpecialForwards extends DeesElement {
|
|
|
132
147
|
};
|
|
133
148
|
}}
|
|
134
149
|
.dataActions=${[
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
150
|
+
...(this.ownerFilter === 'all' || this.ownerFilter === 'operator'
|
|
151
|
+
? [
|
|
152
|
+
{
|
|
153
|
+
name: 'Add HTTP-01 Forward',
|
|
154
|
+
iconName: 'lucide:plus',
|
|
155
|
+
type: ['header' as const],
|
|
156
|
+
actionFunc: async () => this.showForwardDialog(),
|
|
157
|
+
},
|
|
158
|
+
]
|
|
159
|
+
: []),
|
|
141
160
|
{
|
|
142
161
|
name: 'Refresh',
|
|
143
162
|
iconName: 'lucide:refreshCw',
|
|
@@ -148,6 +167,9 @@ export class OpsViewSpecialForwards extends DeesElement {
|
|
|
148
167
|
name: 'Edit',
|
|
149
168
|
iconName: 'lucide:pencil',
|
|
150
169
|
type: ['inRow', 'contextmenu'] as any,
|
|
170
|
+
actionRelevancyCheckFunc: (route: interfaces.data.IMergedRoute) => {
|
|
171
|
+
return getRouteOwner(route) === 'operator';
|
|
172
|
+
},
|
|
151
173
|
actionFunc: async (actionData: any) => {
|
|
152
174
|
await this.showForwardDialog(actionData.item as interfaces.data.IMergedRoute);
|
|
153
175
|
},
|
|
@@ -156,6 +178,9 @@ export class OpsViewSpecialForwards extends DeesElement {
|
|
|
156
178
|
name: 'Enable / Disable',
|
|
157
179
|
iconName: 'lucide:power',
|
|
158
180
|
type: ['inRow', 'contextmenu'] as any,
|
|
181
|
+
actionRelevancyCheckFunc: (route: interfaces.data.IMergedRoute) => {
|
|
182
|
+
return getRouteOwner(route) === 'operator';
|
|
183
|
+
},
|
|
159
184
|
actionFunc: async (actionData: any) => {
|
|
160
185
|
const route = actionData.item as interfaces.data.IMergedRoute;
|
|
161
186
|
await appstate.routeManagementStatePart.dispatchAction(
|
|
@@ -168,6 +193,9 @@ export class OpsViewSpecialForwards extends DeesElement {
|
|
|
168
193
|
name: 'Delete',
|
|
169
194
|
iconName: 'lucide:trash2',
|
|
170
195
|
type: ['inRow', 'contextmenu'] as any,
|
|
196
|
+
actionRelevancyCheckFunc: (route: interfaces.data.IMergedRoute) => {
|
|
197
|
+
return getRouteOwner(route) === 'operator';
|
|
198
|
+
},
|
|
171
199
|
actionFunc: async (actionData: any) => {
|
|
172
200
|
await this.confirmDelete(actionData.item as interfaces.data.IMergedRoute);
|
|
173
201
|
},
|
|
@@ -515,7 +515,7 @@ export class OpsViewVpn extends DeesElement {
|
|
|
515
515
|
name: 'Enable',
|
|
516
516
|
iconName: 'lucide:power',
|
|
517
517
|
type: ['contextmenu', 'inRow'],
|
|
518
|
-
actionRelevancyCheckFunc: (
|
|
518
|
+
actionRelevancyCheckFunc: (client: any) => !client.enabled,
|
|
519
519
|
actionFunc: async (actionData: any) => {
|
|
520
520
|
const client = actionData.item as interfaces.data.IVpnClient;
|
|
521
521
|
await appstate.vpnStatePart.dispatchAction(appstate.toggleVpnClientAction, {
|
|
@@ -528,7 +528,7 @@ export class OpsViewVpn extends DeesElement {
|
|
|
528
528
|
name: 'Disable',
|
|
529
529
|
iconName: 'lucide:power',
|
|
530
530
|
type: ['contextmenu', 'inRow'],
|
|
531
|
-
actionRelevancyCheckFunc: (
|
|
531
|
+
actionRelevancyCheckFunc: (client: any) => client.enabled,
|
|
532
532
|
actionFunc: async (actionData: any) => {
|
|
533
533
|
const client = actionData.item as interfaces.data.IVpnClient;
|
|
534
534
|
await appstate.vpnStatePart.dispatchAction(appstate.toggleVpnClientAction, {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canonicalizeSourceRouteId,
|
|
3
|
+
type IHttpRedirectInfo,
|
|
4
|
+
type IMergedRoute,
|
|
5
|
+
} from '../../../dist_ts_interfaces/data/route-management.js';
|
|
6
|
+
|
|
7
|
+
export type TRouteOwnerFilter = 'all' | 'operator' | 'gatewayClient' | 'system';
|
|
8
|
+
export type TResolvedRouteOwner = Exclude<TRouteOwnerFilter, 'all'>;
|
|
9
|
+
|
|
10
|
+
export function getRouteOwner(route: IMergedRoute): TResolvedRouteOwner {
|
|
11
|
+
if (route.metadata?.ownerType === 'gatewayClient') return 'gatewayClient';
|
|
12
|
+
if (route.metadata?.ownerType === 'system') return 'system';
|
|
13
|
+
if (route.metadata?.ownerType === 'operator') return 'operator';
|
|
14
|
+
return route.origin === 'api' ? 'operator' : 'system';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function routeMatchesOwner(
|
|
18
|
+
route: IMergedRoute,
|
|
19
|
+
ownerFilter: TRouteOwnerFilter,
|
|
20
|
+
): boolean {
|
|
21
|
+
return ownerFilter === 'all' || getRouteOwner(route) === ownerFilter;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getCanonicalRouteIds(route: IMergedRoute): string[] {
|
|
25
|
+
const configuredRouteId = (route.route as { id?: string }).id;
|
|
26
|
+
return [route.id, configuredRouteId]
|
|
27
|
+
.filter((routeId): routeId is string => Boolean(routeId))
|
|
28
|
+
.map(canonicalizeSourceRouteId);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function redirectMatchesOwner(
|
|
32
|
+
redirect: IHttpRedirectInfo,
|
|
33
|
+
mergedRoutes: IMergedRoute[],
|
|
34
|
+
ownerFilter: TRouteOwnerFilter,
|
|
35
|
+
): boolean {
|
|
36
|
+
if (ownerFilter === 'all') return true;
|
|
37
|
+
|
|
38
|
+
const sourceRouteIds = new Set(redirect.sourceRouteIds.map(canonicalizeSourceRouteId));
|
|
39
|
+
return mergedRoutes.some((route) => {
|
|
40
|
+
return getCanonicalRouteIds(route).some((routeId) => sourceRouteIds.has(routeId))
|
|
41
|
+
&& getRouteOwner(route) === ownerFilter;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -268,7 +268,7 @@ export class OpsViewSecurityBlocked extends DeesElement {
|
|
|
268
268
|
name: 'Enable',
|
|
269
269
|
iconName: 'lucide:play',
|
|
270
270
|
type: ['contextmenu'] as any,
|
|
271
|
-
actionRelevancyCheckFunc: (
|
|
271
|
+
actionRelevancyCheckFunc: (entry: any) => !entry.enabled,
|
|
272
272
|
actionFunc: async (actionData: any) => {
|
|
273
273
|
const rule = actionData.item as interfaces.data.ISecurityBlockRule;
|
|
274
274
|
await appstate.securityPolicyStatePart.dispatchAction(appstate.updateSecurityBlockRuleAction, {
|
|
@@ -281,7 +281,7 @@ export class OpsViewSecurityBlocked extends DeesElement {
|
|
|
281
281
|
name: 'Disable',
|
|
282
282
|
iconName: 'lucide:pause',
|
|
283
283
|
type: ['contextmenu'] as any,
|
|
284
|
-
actionRelevancyCheckFunc: (
|
|
284
|
+
actionRelevancyCheckFunc: (entry: any) => entry.enabled,
|
|
285
285
|
actionFunc: async (actionData: any) => {
|
|
286
286
|
const rule = actionData.item as interfaces.data.ISecurityBlockRule;
|
|
287
287
|
await appstate.securityPolicyStatePart.dispatchAction(appstate.updateSecurityBlockRuleAction, {
|
|
@@ -331,7 +331,7 @@ export class OpsViewSecurityBlocked extends DeesElement {
|
|
|
331
331
|
name: 'Block Network Range',
|
|
332
332
|
iconName: 'lucide:network',
|
|
333
333
|
type: ['contextmenu'] as any,
|
|
334
|
-
actionRelevancyCheckFunc: (
|
|
334
|
+
actionRelevancyCheckFunc: (entry: any) => Boolean(entry.networkRange),
|
|
335
335
|
actionFunc: async (actionData: any) => {
|
|
336
336
|
const record = actionData.item as interfaces.data.IIpIntelligenceRecord;
|
|
337
337
|
await this.showRuleDialog(undefined, {
|
|
@@ -345,7 +345,7 @@ export class OpsViewSecurityBlocked extends DeesElement {
|
|
|
345
345
|
name: 'Block ASN',
|
|
346
346
|
iconName: 'lucide:radio-tower',
|
|
347
347
|
type: ['contextmenu'] as any,
|
|
348
|
-
actionRelevancyCheckFunc: (
|
|
348
|
+
actionRelevancyCheckFunc: (entry: any) => Boolean(entry.asn),
|
|
349
349
|
actionFunc: async (actionData: any) => {
|
|
350
350
|
const record = actionData.item as interfaces.data.IIpIntelligenceRecord;
|
|
351
351
|
await this.showRuleDialog(undefined, {
|
|
@@ -359,7 +359,7 @@ export class OpsViewSecurityBlocked extends DeesElement {
|
|
|
359
359
|
name: 'Block Organization',
|
|
360
360
|
iconName: 'lucide:building-2',
|
|
361
361
|
type: ['contextmenu'] as any,
|
|
362
|
-
actionRelevancyCheckFunc: (
|
|
362
|
+
actionRelevancyCheckFunc: (entry: any) => Boolean(entry.asnOrg || entry.registrantOrg),
|
|
363
363
|
actionFunc: async (actionData: any) => {
|
|
364
364
|
const record = actionData.item as interfaces.data.IIpIntelligenceRecord;
|
|
365
365
|
await this.showRuleDialog(undefined, {
|
package/ts_web/readme.md
CHANGED
|
@@ -29,12 +29,12 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
29
29
|
|
|
30
30
|
## Routes Navigation
|
|
31
31
|
|
|
32
|
-
The `/network/routes` view uses two
|
|
32
|
+
The `/network/routes` view uses two adjacent, independent multitoggles:
|
|
33
33
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
34
|
+
- type: **All**, **Standard**, **Redirect**, and **Special**
|
|
35
|
+
- owner: **All**, **User**, **Gateway Client**, and **System**
|
|
36
36
|
|
|
37
|
-
Special
|
|
37
|
+
The owner selection filters every displayed route projection. **All** keeps Standard, Special, and Redirect routes in separate sections rather than mixing unlike rows. Special routes include managed Let's Encrypt HTTP-01 forwards for exact domains and a selected inline or Network Target backend; non-user routes are read-only. Redirects remain a derived runtime view and inherit ownership from their canonical source routes. Filter state is stored in the `tab` and `owner` query parameters so deep links and browser history remain stable; the legacy `/network/redirects` URL is normalized to `/network/routes?tab=redirects`.
|
|
38
38
|
|
|
39
39
|
## Runtime Communication
|
|
40
40
|
|