@serve.zone/dcrouter 12.2.5 → 12.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/dist_serve/bundle.js +944 -748
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/ops-dashboard.d.ts +2 -0
- package/dist_ts_web/elements/ops-dashboard.js +35 -2
- package/dist_ts_web/elements/ops-view-networktargets.js +21 -14
- package/dist_ts_web/elements/ops-view-securityprofiles.js +21 -14
- package/package.json +3 -3
- package/readme.md +77 -63
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/ops-dashboard.ts +29 -1
- package/ts_web/elements/ops-view-networktargets.ts +18 -13
- package/ts_web/elements/ops-view-securityprofiles.ts +18 -13
- package/ts_web/readme.md +6 -0
package/readme.md
CHANGED
|
@@ -93,10 +93,11 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
93
93
|
- **Socket-handler mode** — direct socket passing eliminates internal port hops
|
|
94
94
|
- **Real-time metrics** via SmartMetrics (CPU, memory, connections, throughput)
|
|
95
95
|
|
|
96
|
-
### 💾
|
|
97
|
-
- **
|
|
98
|
-
- **
|
|
96
|
+
### 💾 Unified Database
|
|
97
|
+
- **Two deployment modes**: embedded LocalSmartDb (zero-config) or external MongoDB
|
|
98
|
+
- **15 document classes** covering routes, certs, VPN, RADIUS, security profiles, network targets, and caches
|
|
99
99
|
- **Automatic TTL-based cleanup** for cached emails and IP reputation data
|
|
100
|
+
- **Reusable references** — security profiles and network targets that propagate changes to all referencing routes
|
|
100
101
|
|
|
101
102
|
### 🖥️ OpsServer Dashboard
|
|
102
103
|
- **Web-based management interface** with real-time monitoring
|
|
@@ -104,7 +105,9 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
104
105
|
- **Live views** for connections, email queues, DNS queries, RADIUS sessions, certificates, remote ingress edges, VPN clients, and security events
|
|
105
106
|
- **Domain-centric certificate overview** with backoff status and one-click reprovisioning
|
|
106
107
|
- **Remote ingress management** with connection token generation and one-click copy
|
|
107
|
-
- **
|
|
108
|
+
- **Security profiles & network targets** — reusable security configurations and host:port targets with propagation to referencing routes
|
|
109
|
+
- **Global warning banners** when database is disabled (management features unavailable)
|
|
110
|
+
- **Read-only configuration display** for system overview
|
|
108
111
|
- **Smart tab visibility handling** — auto-pauses all polling, WebSocket connections, and chart updates when the browser tab is hidden, preventing resource waste and tab freezing
|
|
109
112
|
|
|
110
113
|
### 🔧 Programmatic API Client
|
|
@@ -269,11 +272,8 @@ const router = new DcRouter({
|
|
|
269
272
|
],
|
|
270
273
|
},
|
|
271
274
|
|
|
272
|
-
//
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
// Cache database
|
|
276
|
-
cacheConfig: { enabled: true, storagePath: '~/.serve.zone/dcrouter/tsmdb' },
|
|
275
|
+
// Unified database (embedded LocalSmartDb or external MongoDB)
|
|
276
|
+
dbConfig: { enabled: true },
|
|
277
277
|
|
|
278
278
|
// TLS & ACME
|
|
279
279
|
tls: { contactEmail: 'admin@example.com' },
|
|
@@ -311,8 +311,7 @@ graph TB
|
|
|
311
311
|
CM[Certificate Manager<br/><i>smartacme v9</i>]
|
|
312
312
|
OS[OpsServer Dashboard]
|
|
313
313
|
MM[Metrics Manager]
|
|
314
|
-
|
|
315
|
-
CD[Cache Database]
|
|
314
|
+
DB2[DcRouterDb<br/><i>smartdata + smartdb</i>]
|
|
316
315
|
end
|
|
317
316
|
|
|
318
317
|
subgraph "Backend Services"
|
|
@@ -339,8 +338,7 @@ graph TB
|
|
|
339
338
|
DC --> CM
|
|
340
339
|
DC --> OS
|
|
341
340
|
DC --> MM
|
|
342
|
-
DC -->
|
|
343
|
-
DC --> CD
|
|
341
|
+
DC --> DB2
|
|
344
342
|
|
|
345
343
|
SP --> WEB
|
|
346
344
|
SP --> API
|
|
@@ -365,8 +363,7 @@ graph TB
|
|
|
365
363
|
| **RemoteIngress** | `@serve.zone/remoteingress` | Distributed edge tunneling with Rust data plane and TS management |
|
|
366
364
|
| **OpsServer** | `@api.global/typedserver` | Web dashboard + TypedRequest API for monitoring and management |
|
|
367
365
|
| **MetricsManager** | `@push.rocks/smartmetrics` | Real-time metrics collection (CPU, memory, email, DNS, security) |
|
|
368
|
-
| **
|
|
369
|
-
| **CacheDb** | `@push.rocks/smartdb` | Embedded MongoDB-compatible database (LocalSmartDb) for persistent caching |
|
|
366
|
+
| **DcRouterDb** | `@push.rocks/smartdata` + `@push.rocks/smartdb` | Unified database — embedded LocalSmartDb or external MongoDB for all persistence |
|
|
370
367
|
|
|
371
368
|
### How It Works
|
|
372
369
|
|
|
@@ -509,24 +506,16 @@ interface IDcRouterOptions {
|
|
|
509
506
|
};
|
|
510
507
|
dnsChallenge?: { cloudflareApiKey?: string };
|
|
511
508
|
|
|
512
|
-
// ──
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
readFunction?: (key: string) => Promise<string>;
|
|
516
|
-
writeFunction?: (key: string, value: string) => Promise<void>;
|
|
517
|
-
};
|
|
518
|
-
cacheConfig?: {
|
|
509
|
+
// ── Database ────────────────────────────────────────────────────
|
|
510
|
+
/** Unified database for all persistence (routes, certs, VPN, RADIUS, etc.) */
|
|
511
|
+
dbConfig?: {
|
|
519
512
|
enabled?: boolean; // default: true
|
|
513
|
+
mongoDbUrl?: string; // External MongoDB URL (omit for embedded LocalSmartDb)
|
|
520
514
|
storagePath?: string; // default: '~/.serve.zone/dcrouter/tsmdb'
|
|
521
515
|
dbName?: string; // default: 'dcrouter'
|
|
522
516
|
cleanupIntervalHours?: number; // default: 1
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
ipReputation?: number; // default: 1 day
|
|
526
|
-
bounces?: number; // default: 30 days
|
|
527
|
-
dkimKeys?: number; // default: 90 days
|
|
528
|
-
suppression?: number; // default: 30 days
|
|
529
|
-
};
|
|
517
|
+
seedOnEmpty?: boolean; // Seed default profiles/targets if DB is empty
|
|
518
|
+
seedData?: object; // Custom seed data
|
|
530
519
|
};
|
|
531
520
|
}
|
|
532
521
|
```
|
|
@@ -1213,49 +1202,55 @@ The OpsServer includes a **Certificates** view showing:
|
|
|
1213
1202
|
- One-click reprovisioning per domain
|
|
1214
1203
|
- Certificate import and export
|
|
1215
1204
|
|
|
1216
|
-
## Storage &
|
|
1205
|
+
## Storage & Database
|
|
1217
1206
|
|
|
1218
|
-
|
|
1207
|
+
DcRouter uses a **unified database** (`DcRouterDb`) powered by [`@push.rocks/smartdata`](https://code.foss.global/push.rocks/smartdata) + [`@push.rocks/smartdb`](https://code.foss.global/push.rocks/smartdb) for all persistence. It supports two modes:
|
|
1219
1208
|
|
|
1220
|
-
|
|
1209
|
+
### Embedded LocalSmartDb (Default)
|
|
1221
1210
|
|
|
1222
|
-
|
|
1223
|
-
// Filesystem backend
|
|
1224
|
-
storage: { fsPath: '/var/lib/dcrouter/data' }
|
|
1211
|
+
Zero-config, file-based MongoDB-compatible database — no external services needed:
|
|
1225
1212
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
writeFunction: async (key, value) => await redis.set(key, value)
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
// In-memory (development only — data lost on restart)
|
|
1233
|
-
// Simply omit the storage config
|
|
1213
|
+
```typescript
|
|
1214
|
+
dbConfig: { enabled: true }
|
|
1215
|
+
// Data stored at ~/.serve.zone/dcrouter/tsmdb by default
|
|
1234
1216
|
```
|
|
1235
1217
|
|
|
1236
|
-
|
|
1218
|
+
### External MongoDB
|
|
1237
1219
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
An embedded MongoDB-compatible database (via smartdata + smartdb) for persistent caching with automatic TTL cleanup:
|
|
1220
|
+
Connect to an existing MongoDB instance:
|
|
1241
1221
|
|
|
1242
1222
|
```typescript
|
|
1243
|
-
|
|
1223
|
+
dbConfig: {
|
|
1244
1224
|
enabled: true,
|
|
1245
|
-
|
|
1225
|
+
mongoDbUrl: 'mongodb://localhost:27017',
|
|
1246
1226
|
dbName: 'dcrouter',
|
|
1247
|
-
cleanupIntervalHours: 1,
|
|
1248
|
-
ttlConfig: {
|
|
1249
|
-
emails: 30, // days
|
|
1250
|
-
ipReputation: 1, // days
|
|
1251
|
-
bounces: 30, // days
|
|
1252
|
-
dkimKeys: 90, // days
|
|
1253
|
-
suppression: 30 // days
|
|
1254
|
-
}
|
|
1255
1227
|
}
|
|
1256
1228
|
```
|
|
1257
1229
|
|
|
1258
|
-
|
|
1230
|
+
### Disabling the Database
|
|
1231
|
+
|
|
1232
|
+
For static, constructor-only deployments where no runtime management is needed:
|
|
1233
|
+
|
|
1234
|
+
```typescript
|
|
1235
|
+
dbConfig: { enabled: false }
|
|
1236
|
+
// Routes come exclusively from constructor config — no CRUD, no persistence
|
|
1237
|
+
// OpsServer still runs but management features are disabled
|
|
1238
|
+
```
|
|
1239
|
+
|
|
1240
|
+
### What's Stored
|
|
1241
|
+
|
|
1242
|
+
DcRouterDb persists all runtime state across 15 document classes:
|
|
1243
|
+
|
|
1244
|
+
| Category | Documents | Purpose |
|
|
1245
|
+
|----------|-----------|---------|
|
|
1246
|
+
| **Routes** | `StoredRouteDoc`, `RouteOverrideDoc` | Programmatic routes and hardcoded route overrides |
|
|
1247
|
+
| **Certificates** | `ProxyCertDoc`, `AcmeCertDoc`, `CertBackoffDoc` | TLS certs, ACME state, per-domain backoff |
|
|
1248
|
+
| **Auth** | `ApiTokenDoc` | API token storage |
|
|
1249
|
+
| **Remote Ingress** | `RemoteIngressEdgeDoc` | Edge node registrations |
|
|
1250
|
+
| **VPN** | `VpnServerKeysDoc`, `VpnClientDoc` | Server keys and client registrations |
|
|
1251
|
+
| **RADIUS** | `VlanMappingsDoc`, `AccountingSessionDoc` | VLAN mappings and accounting sessions |
|
|
1252
|
+
| **References** | `SecurityProfileDoc`, `NetworkTargetDoc` | Reusable security profiles and network targets |
|
|
1253
|
+
| **Cache** | `CachedEmailDoc`, `CachedIpReputationDoc` | TTL-based caches with automatic cleanup |
|
|
1259
1254
|
|
|
1260
1255
|
## Security Features
|
|
1261
1256
|
|
|
@@ -1324,6 +1319,8 @@ The OpsServer provides a web-based management interface served on port 3000 by d
|
|
|
1324
1319
|
| 🔐 **Certificates** | Domain-centric certificate overview, status, backoff info, reprovisioning, import/export |
|
|
1325
1320
|
| 🌍 **RemoteIngress** | Edge node management, connection status, token generation, enable/disable |
|
|
1326
1321
|
| 🔐 **VPN** | VPN client management, server status, create/toggle/export/rotate/delete clients |
|
|
1322
|
+
| 🛡️ **Security Profiles** | Reusable security configurations (IP allow/block lists, rate limits) |
|
|
1323
|
+
| 🎯 **Network Targets** | Reusable host:port destinations for route references |
|
|
1327
1324
|
| 📡 **RADIUS** | NAS client management, VLAN mappings, session monitoring, accounting |
|
|
1328
1325
|
| 📜 **Logs** | Real-time log viewer with level filtering and search |
|
|
1329
1326
|
| ⚙️ **Configuration** | Read-only view of current system configuration |
|
|
@@ -1410,6 +1407,22 @@ All management is done via TypedRequest over HTTP POST to `/typedrequest`:
|
|
|
1410
1407
|
'setVlanMapping' // Add/update VLAN mapping
|
|
1411
1408
|
'removeVlanMapping' // Remove VLAN mapping
|
|
1412
1409
|
'testVlanAssignment' // Test what VLAN a MAC gets
|
|
1410
|
+
|
|
1411
|
+
// Security Profiles
|
|
1412
|
+
'getSecurityProfiles' // List all security profiles
|
|
1413
|
+
'getSecurityProfile' // Get a single profile by ID
|
|
1414
|
+
'createSecurityProfile' // Create a reusable security profile
|
|
1415
|
+
'updateSecurityProfile' // Update a profile (propagates to referencing routes)
|
|
1416
|
+
'deleteSecurityProfile' // Delete a profile (with optional force)
|
|
1417
|
+
'getSecurityProfileUsage' // Get routes referencing a profile
|
|
1418
|
+
|
|
1419
|
+
// Network Targets
|
|
1420
|
+
'getNetworkTargets' // List all network targets
|
|
1421
|
+
'getNetworkTarget' // Get a single target by ID
|
|
1422
|
+
'createNetworkTarget' // Create a reusable host:port target
|
|
1423
|
+
'updateNetworkTarget' // Update a target (propagates to referencing routes)
|
|
1424
|
+
'deleteNetworkTarget' // Delete a target (with optional force)
|
|
1425
|
+
'getNetworkTargetUsage' // Get routes referencing a target
|
|
1413
1426
|
```
|
|
1414
1427
|
|
|
1415
1428
|
## API Client
|
|
@@ -1518,12 +1531,12 @@ const router = new DcRouter(options: IDcRouterOptions);
|
|
|
1518
1531
|
| `remoteIngressManager` | `RemoteIngressManager` | Edge registration CRUD manager |
|
|
1519
1532
|
| `tunnelManager` | `TunnelManager` | Tunnel lifecycle and status manager |
|
|
1520
1533
|
| `vpnManager` | `VpnManager` | VPN server lifecycle and client CRUD manager |
|
|
1521
|
-
| `storageManager` | `StorageManager` | Storage backend |
|
|
1522
1534
|
| `opsServer` | `OpsServer` | OpsServer/dashboard instance |
|
|
1523
1535
|
| `metricsManager` | `MetricsManager` | Metrics collector |
|
|
1524
|
-
| `
|
|
1525
|
-
| `
|
|
1526
|
-
| `
|
|
1536
|
+
| `dcRouterDb` | `DcRouterDb` | Unified database instance (smartdata + smartdb) |
|
|
1537
|
+
| `routeConfigManager` | `RouteConfigManager` | Programmatic route CRUD manager |
|
|
1538
|
+
| `apiTokenManager` | `ApiTokenManager` | API token management |
|
|
1539
|
+
| `referenceResolver` | `ReferenceResolver` | Security profile and network target resolver |
|
|
1527
1540
|
|
|
1528
1541
|
### Re-exported Types
|
|
1529
1542
|
|
|
@@ -1589,7 +1602,8 @@ tstest test/test.opsserver-api.ts --verbose --timeout 60
|
|
|
1589
1602
|
| `test.jwt-auth.ts` | JWT login, verification, logout, invalid credentials | 8 |
|
|
1590
1603
|
| `test.opsserver-api.ts` | Health, statistics, configuration, log APIs | 8 |
|
|
1591
1604
|
| `test.protected-endpoint.ts` | Admin auth, identity verification, public endpoints | 8 |
|
|
1592
|
-
| `test.
|
|
1605
|
+
| `test.reference-resolver.ts` | Security profiles, network targets, route resolution | 20 |
|
|
1606
|
+
| `test.security-profiles-api.ts` | Profile/target API endpoints, auth enforcement | 13 |
|
|
1593
1607
|
|
|
1594
1608
|
## Docker / OCI Container Deployment
|
|
1595
1609
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -2,7 +2,6 @@ import * as plugins from '../plugins.js';
|
|
|
2
2
|
import * as appstate from '../appstate.js';
|
|
3
3
|
import * as interfaces from '../../dist_ts_interfaces/index.js';
|
|
4
4
|
import { appRouter } from '../router.js';
|
|
5
|
-
|
|
6
5
|
import {
|
|
7
6
|
DeesElement,
|
|
8
7
|
css,
|
|
@@ -43,6 +42,12 @@ export class OpsDashboard extends DeesElement {
|
|
|
43
42
|
theme: 'light',
|
|
44
43
|
};
|
|
45
44
|
|
|
45
|
+
@state() accessor configState: appstate.IConfigState = {
|
|
46
|
+
config: null,
|
|
47
|
+
isLoading: false,
|
|
48
|
+
error: null,
|
|
49
|
+
};
|
|
50
|
+
|
|
46
51
|
// Store viewTabs as a property to maintain object references
|
|
47
52
|
private viewTabs = [
|
|
48
53
|
{
|
|
@@ -112,6 +117,20 @@ export class OpsDashboard extends DeesElement {
|
|
|
112
117
|
},
|
|
113
118
|
];
|
|
114
119
|
|
|
120
|
+
private get globalMessages() {
|
|
121
|
+
const messages: Array<{ id: string; type: string; message: string; dismissible?: boolean }> = [];
|
|
122
|
+
const config = this.configState.config;
|
|
123
|
+
if (config && !config.cache.enabled) {
|
|
124
|
+
messages.push({
|
|
125
|
+
id: 'db-disabled',
|
|
126
|
+
type: 'warning',
|
|
127
|
+
message: 'Database is disabled. Creating and editing routes, profiles, targets, and API tokens is not available.',
|
|
128
|
+
dismissible: false,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return messages;
|
|
132
|
+
}
|
|
133
|
+
|
|
115
134
|
/**
|
|
116
135
|
* Get the current view tab based on the UI state's activeView.
|
|
117
136
|
* Used to pass the correct selectedView to dees-simple-appdash on initial render.
|
|
@@ -137,6 +156,14 @@ export class OpsDashboard extends DeesElement {
|
|
|
137
156
|
});
|
|
138
157
|
this.rxSubscriptions.push(loginSubscription);
|
|
139
158
|
|
|
159
|
+
// Subscribe to config state (for global warnings)
|
|
160
|
+
const configSubscription = appstate.configStatePart
|
|
161
|
+
.select((stateArg) => stateArg)
|
|
162
|
+
.subscribe((configState) => {
|
|
163
|
+
this.configState = configState;
|
|
164
|
+
});
|
|
165
|
+
this.rxSubscriptions.push(configSubscription);
|
|
166
|
+
|
|
140
167
|
// Subscribe to UI state
|
|
141
168
|
const uiSubscription = appstate.uiStatePart
|
|
142
169
|
.select((stateArg) => stateArg)
|
|
@@ -205,6 +232,7 @@ export class OpsDashboard extends DeesElement {
|
|
|
205
232
|
name="DCRouter OpsServer"
|
|
206
233
|
.viewTabs=${this.viewTabs}
|
|
207
234
|
.selectedView=${this.currentViewTab}
|
|
235
|
+
.globalMessages=${this.globalMessages}
|
|
208
236
|
>
|
|
209
237
|
</dees-simple-appdash>
|
|
210
238
|
</dees-simple-login>
|
|
@@ -64,6 +64,7 @@ export class OpsViewNetworkTargets extends DeesElement {
|
|
|
64
64
|
];
|
|
65
65
|
|
|
66
66
|
return html`
|
|
67
|
+
<ops-sectionheading>Network Targets</ops-sectionheading>
|
|
67
68
|
<div class="targetsContainer">
|
|
68
69
|
<dees-statsgrid .tiles=${statsTiles}></dees-statsgrid>
|
|
69
70
|
<dees-table
|
|
@@ -81,8 +82,8 @@ export class OpsViewNetworkTargets extends DeesElement {
|
|
|
81
82
|
name: 'Create Target',
|
|
82
83
|
iconName: 'lucide:plus',
|
|
83
84
|
type: ['header' as const],
|
|
84
|
-
actionFunc: async (
|
|
85
|
-
await this.showCreateTargetDialog(
|
|
85
|
+
actionFunc: async () => {
|
|
86
|
+
await this.showCreateTargetDialog();
|
|
86
87
|
},
|
|
87
88
|
},
|
|
88
89
|
{
|
|
@@ -96,16 +97,18 @@ export class OpsViewNetworkTargets extends DeesElement {
|
|
|
96
97
|
{
|
|
97
98
|
name: 'Edit',
|
|
98
99
|
iconName: 'lucide:pencil',
|
|
99
|
-
type: ['contextmenu' as
|
|
100
|
-
actionFunc: async (
|
|
101
|
-
|
|
100
|
+
type: ['inRow', 'contextmenu'] as any,
|
|
101
|
+
actionFunc: async (actionData: any) => {
|
|
102
|
+
const target = actionData.item as interfaces.data.INetworkTarget;
|
|
103
|
+
await this.showEditTargetDialog(target);
|
|
102
104
|
},
|
|
103
105
|
},
|
|
104
106
|
{
|
|
105
107
|
name: 'Delete',
|
|
106
108
|
iconName: 'lucide:trash2',
|
|
107
|
-
type: ['contextmenu' as
|
|
108
|
-
actionFunc: async (
|
|
109
|
+
type: ['inRow', 'contextmenu'] as any,
|
|
110
|
+
actionFunc: async (actionData: any) => {
|
|
111
|
+
const target = actionData.item as interfaces.data.INetworkTarget;
|
|
109
112
|
await this.deleteTarget(target);
|
|
110
113
|
},
|
|
111
114
|
},
|
|
@@ -115,7 +118,7 @@ export class OpsViewNetworkTargets extends DeesElement {
|
|
|
115
118
|
`;
|
|
116
119
|
}
|
|
117
120
|
|
|
118
|
-
private async showCreateTargetDialog(
|
|
121
|
+
private async showCreateTargetDialog() {
|
|
119
122
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
120
123
|
DeesModal.createAndShow({
|
|
121
124
|
heading: 'Create Network Target',
|
|
@@ -128,10 +131,12 @@ export class OpsViewNetworkTargets extends DeesElement {
|
|
|
128
131
|
</dees-form>
|
|
129
132
|
`,
|
|
130
133
|
menuOptions: [
|
|
134
|
+
{ name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
|
|
131
135
|
{
|
|
132
136
|
name: 'Create',
|
|
133
137
|
action: async (modalArg: any) => {
|
|
134
|
-
const form = modalArg.shadowRoot
|
|
138
|
+
const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
|
|
139
|
+
if (!form) return;
|
|
135
140
|
const data = await form.collectFormData();
|
|
136
141
|
|
|
137
142
|
await appstate.profilesTargetsStatePart.dispatchAction(appstate.createTargetAction, {
|
|
@@ -143,12 +148,11 @@ export class OpsViewNetworkTargets extends DeesElement {
|
|
|
143
148
|
modalArg.destroy();
|
|
144
149
|
},
|
|
145
150
|
},
|
|
146
|
-
{ name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
|
|
147
151
|
],
|
|
148
152
|
});
|
|
149
153
|
}
|
|
150
154
|
|
|
151
|
-
private async showEditTargetDialog(target: interfaces.data.INetworkTarget
|
|
155
|
+
private async showEditTargetDialog(target: interfaces.data.INetworkTarget) {
|
|
152
156
|
const hostStr = Array.isArray(target.host) ? target.host.join(', ') : target.host;
|
|
153
157
|
|
|
154
158
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
@@ -163,10 +167,12 @@ export class OpsViewNetworkTargets extends DeesElement {
|
|
|
163
167
|
</dees-form>
|
|
164
168
|
`,
|
|
165
169
|
menuOptions: [
|
|
170
|
+
{ name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
|
|
166
171
|
{
|
|
167
172
|
name: 'Save',
|
|
168
173
|
action: async (modalArg: any) => {
|
|
169
|
-
const form = modalArg.shadowRoot
|
|
174
|
+
const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
|
|
175
|
+
if (!form) return;
|
|
170
176
|
const data = await form.collectFormData();
|
|
171
177
|
|
|
172
178
|
await appstate.profilesTargetsStatePart.dispatchAction(appstate.updateTargetAction, {
|
|
@@ -179,7 +185,6 @@ export class OpsViewNetworkTargets extends DeesElement {
|
|
|
179
185
|
modalArg.destroy();
|
|
180
186
|
},
|
|
181
187
|
},
|
|
182
|
-
{ name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
|
|
183
188
|
],
|
|
184
189
|
});
|
|
185
190
|
}
|
|
@@ -64,6 +64,7 @@ export class OpsViewSecurityProfiles extends DeesElement {
|
|
|
64
64
|
];
|
|
65
65
|
|
|
66
66
|
return html`
|
|
67
|
+
<ops-sectionheading>Security Profiles</ops-sectionheading>
|
|
67
68
|
<div class="profilesContainer">
|
|
68
69
|
<dees-statsgrid .tiles=${statsTiles}></dees-statsgrid>
|
|
69
70
|
<dees-table
|
|
@@ -89,8 +90,8 @@ export class OpsViewSecurityProfiles extends DeesElement {
|
|
|
89
90
|
name: 'Create Profile',
|
|
90
91
|
iconName: 'lucide:plus',
|
|
91
92
|
type: ['header' as const],
|
|
92
|
-
actionFunc: async (
|
|
93
|
-
await this.showCreateProfileDialog(
|
|
93
|
+
actionFunc: async () => {
|
|
94
|
+
await this.showCreateProfileDialog();
|
|
94
95
|
},
|
|
95
96
|
},
|
|
96
97
|
{
|
|
@@ -104,16 +105,18 @@ export class OpsViewSecurityProfiles extends DeesElement {
|
|
|
104
105
|
{
|
|
105
106
|
name: 'Edit',
|
|
106
107
|
iconName: 'lucide:pencil',
|
|
107
|
-
type: ['contextmenu' as
|
|
108
|
-
actionFunc: async (
|
|
109
|
-
|
|
108
|
+
type: ['inRow', 'contextmenu'] as any,
|
|
109
|
+
actionFunc: async (actionData: any) => {
|
|
110
|
+
const profile = actionData.item as interfaces.data.ISecurityProfile;
|
|
111
|
+
await this.showEditProfileDialog(profile);
|
|
110
112
|
},
|
|
111
113
|
},
|
|
112
114
|
{
|
|
113
115
|
name: 'Delete',
|
|
114
116
|
iconName: 'lucide:trash2',
|
|
115
|
-
type: ['contextmenu' as
|
|
116
|
-
actionFunc: async (
|
|
117
|
+
type: ['inRow', 'contextmenu'] as any,
|
|
118
|
+
actionFunc: async (actionData: any) => {
|
|
119
|
+
const profile = actionData.item as interfaces.data.ISecurityProfile;
|
|
117
120
|
await this.deleteProfile(profile);
|
|
118
121
|
},
|
|
119
122
|
},
|
|
@@ -123,7 +126,7 @@ export class OpsViewSecurityProfiles extends DeesElement {
|
|
|
123
126
|
`;
|
|
124
127
|
}
|
|
125
128
|
|
|
126
|
-
private async showCreateProfileDialog(
|
|
129
|
+
private async showCreateProfileDialog() {
|
|
127
130
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
128
131
|
DeesModal.createAndShow({
|
|
129
132
|
heading: 'Create Security Profile',
|
|
@@ -137,10 +140,12 @@ export class OpsViewSecurityProfiles extends DeesElement {
|
|
|
137
140
|
</dees-form>
|
|
138
141
|
`,
|
|
139
142
|
menuOptions: [
|
|
143
|
+
{ name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
|
|
140
144
|
{
|
|
141
145
|
name: 'Create',
|
|
142
146
|
action: async (modalArg: any) => {
|
|
143
|
-
const form = modalArg.shadowRoot
|
|
147
|
+
const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
|
|
148
|
+
if (!form) return;
|
|
144
149
|
const data = await form.collectFormData();
|
|
145
150
|
const ipAllowList: string[] = Array.isArray(data.ipAllowList) ? data.ipAllowList : [];
|
|
146
151
|
const ipBlockList: string[] = Array.isArray(data.ipBlockList) ? data.ipBlockList : [];
|
|
@@ -158,12 +163,11 @@ export class OpsViewSecurityProfiles extends DeesElement {
|
|
|
158
163
|
modalArg.destroy();
|
|
159
164
|
},
|
|
160
165
|
},
|
|
161
|
-
{ name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
|
|
162
166
|
],
|
|
163
167
|
});
|
|
164
168
|
}
|
|
165
169
|
|
|
166
|
-
private async showEditProfileDialog(profile: interfaces.data.ISecurityProfile
|
|
170
|
+
private async showEditProfileDialog(profile: interfaces.data.ISecurityProfile) {
|
|
167
171
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
168
172
|
DeesModal.createAndShow({
|
|
169
173
|
heading: `Edit Profile: ${profile.name}`,
|
|
@@ -177,10 +181,12 @@ export class OpsViewSecurityProfiles extends DeesElement {
|
|
|
177
181
|
</dees-form>
|
|
178
182
|
`,
|
|
179
183
|
menuOptions: [
|
|
184
|
+
{ name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
|
|
180
185
|
{
|
|
181
186
|
name: 'Save',
|
|
182
187
|
action: async (modalArg: any) => {
|
|
183
|
-
const form = modalArg.shadowRoot
|
|
188
|
+
const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form');
|
|
189
|
+
if (!form) return;
|
|
184
190
|
const data = await form.collectFormData();
|
|
185
191
|
const ipAllowList: string[] = Array.isArray(data.ipAllowList) ? data.ipAllowList : [];
|
|
186
192
|
const ipBlockList: string[] = Array.isArray(data.ipBlockList) ? data.ipBlockList : [];
|
|
@@ -199,7 +205,6 @@ export class OpsViewSecurityProfiles extends DeesElement {
|
|
|
199
205
|
modalArg.destroy();
|
|
200
206
|
},
|
|
201
207
|
},
|
|
202
|
-
{ name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() },
|
|
203
208
|
],
|
|
204
209
|
});
|
|
205
210
|
}
|
package/ts_web/readme.md
CHANGED
|
@@ -68,6 +68,12 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
68
68
|
- API token creation, revocation, and scope management
|
|
69
69
|
- Routes tab and API Tokens tab in unified view
|
|
70
70
|
|
|
71
|
+
### 🛡️ Security Profiles & Network Targets
|
|
72
|
+
- Create, edit, and delete reusable security profiles (IP allow/block lists, rate limits, max connections)
|
|
73
|
+
- Create, edit, and delete reusable network targets (host:port destinations)
|
|
74
|
+
- In-row and context menu actions for quick editing
|
|
75
|
+
- Changes propagate automatically to all referencing routes
|
|
76
|
+
|
|
71
77
|
### ⚙️ Configuration
|
|
72
78
|
- Read-only display of current system configuration
|
|
73
79
|
- Status badges for boolean values (enabled/disabled)
|