@serve.zone/dcrouter 8.1.0 → 9.1.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 +1417 -992
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/monitoring/classes.metricsmanager.d.ts +169 -0
- package/dist_ts/monitoring/classes.metricsmanager.js +591 -0
- package/dist_ts/monitoring/index.d.ts +1 -0
- package/dist_ts/monitoring/index.js +2 -0
- package/dist_ts/opsserver/handlers/certificate.handler.d.ts +34 -0
- package/dist_ts/opsserver/handlers/certificate.handler.js +419 -0
- package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +32 -0
- package/dist_ts/opsserver/handlers/email-ops.handler.js +226 -0
- package/dist_ts/opsserver/handlers/radius.handler.d.ts +8 -0
- package/dist_ts/opsserver/handlers/radius.handler.js +296 -0
- package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +8 -0
- package/dist_ts/opsserver/handlers/remoteingress.handler.js +154 -0
- package/dist_ts/opsserver/handlers/security.handler.d.ts +11 -0
- package/dist_ts/opsserver/handlers/security.handler.js +232 -0
- package/dist_ts/opsserver/handlers/stats.handler.d.ts +13 -0
- package/dist_ts/opsserver/handlers/stats.handler.js +400 -0
- package/dist_ts/security/classes.securitylogger.d.ts +140 -0
- package/dist_ts_interfaces/requests/config.d.ts +77 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +1 -1
- package/dist_ts_web/elements/ops-dashboard.js +15 -5
- package/dist_ts_web/elements/ops-view-apitokens.js +8 -4
- package/dist_ts_web/elements/ops-view-config.d.ts +10 -8
- package/dist_ts_web/elements/ops-view-config.js +215 -297
- package/package.json +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/opsserver/handlers/config.handler.ts +154 -72
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +1 -1
- package/ts_web/elements/ops-dashboard.ts +14 -4
- package/ts_web/elements/ops-view-apitokens.ts +7 -3
- package/ts_web/elements/ops-view-config.ts +237 -299
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
|
+
import * as paths from '../../paths.js';
|
|
2
3
|
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
4
|
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
4
5
|
|
|
@@ -17,7 +18,7 @@ export class ConfigHandler {
|
|
|
17
18
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetConfiguration>(
|
|
18
19
|
'getConfiguration',
|
|
19
20
|
async (dataArg, toolsArg) => {
|
|
20
|
-
const config = await this.getConfiguration(
|
|
21
|
+
const config = await this.getConfiguration();
|
|
21
22
|
return {
|
|
22
23
|
config,
|
|
23
24
|
section: dataArg.section,
|
|
@@ -26,83 +27,164 @@ export class ConfigHandler {
|
|
|
26
27
|
)
|
|
27
28
|
);
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
-
private async getConfiguration(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
enabled: boolean;
|
|
51
|
-
httpPort: number;
|
|
52
|
-
httpsPort: number;
|
|
53
|
-
maxConnections: number;
|
|
30
|
+
|
|
31
|
+
private async getConfiguration(): Promise<interfaces.requests.IConfigData> {
|
|
32
|
+
const dcRouter = this.opsServerRef.dcRouterRef;
|
|
33
|
+
const opts = dcRouter.options;
|
|
34
|
+
const resolvedPaths = dcRouter.resolvedPaths;
|
|
35
|
+
|
|
36
|
+
// --- System ---
|
|
37
|
+
const storageBackend: 'filesystem' | 'custom' | 'memory' = opts.storage?.readFunction
|
|
38
|
+
? 'custom'
|
|
39
|
+
: opts.storage?.fsPath
|
|
40
|
+
? 'filesystem'
|
|
41
|
+
: 'memory';
|
|
42
|
+
|
|
43
|
+
const system: interfaces.requests.IConfigData['system'] = {
|
|
44
|
+
baseDir: resolvedPaths.dcrouterHomeDir,
|
|
45
|
+
dataDir: resolvedPaths.dataDir,
|
|
46
|
+
publicIp: opts.publicIp || null,
|
|
47
|
+
proxyIps: opts.proxyIps || [],
|
|
48
|
+
uptime: Math.floor(process.uptime()),
|
|
49
|
+
storageBackend,
|
|
50
|
+
storagePath: opts.storage?.fsPath || null,
|
|
54
51
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
|
|
53
|
+
// --- SmartProxy ---
|
|
54
|
+
let acmeInfo: interfaces.requests.IConfigData['smartProxy']['acme'] = null;
|
|
55
|
+
if (opts.smartProxyConfig?.acme) {
|
|
56
|
+
const acme = opts.smartProxyConfig.acme;
|
|
57
|
+
acmeInfo = {
|
|
58
|
+
enabled: acme.enabled !== false,
|
|
59
|
+
accountEmail: acme.accountEmail || '',
|
|
60
|
+
useProduction: acme.useProduction !== false,
|
|
61
|
+
autoRenew: acme.autoRenew !== false,
|
|
62
|
+
renewThresholdDays: acme.renewThresholdDays || 30,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let routeCount = 0;
|
|
67
|
+
if (dcRouter.routeConfigManager) {
|
|
68
|
+
try {
|
|
69
|
+
const merged = await dcRouter.routeConfigManager.getMergedRoutes();
|
|
70
|
+
routeCount = merged.routes.length;
|
|
71
|
+
} catch {
|
|
72
|
+
routeCount = opts.smartProxyConfig?.routes?.length || 0;
|
|
73
|
+
}
|
|
74
|
+
} else if (opts.smartProxyConfig?.routes) {
|
|
75
|
+
routeCount = opts.smartProxyConfig.routes.length;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const smartProxy: interfaces.requests.IConfigData['smartProxy'] = {
|
|
79
|
+
enabled: !!dcRouter.smartProxy,
|
|
80
|
+
routeCount,
|
|
81
|
+
acme: acmeInfo,
|
|
60
82
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// Get email domains if email server is configured
|
|
83
|
+
|
|
84
|
+
// --- Email ---
|
|
65
85
|
let emailDomains: string[] = [];
|
|
66
|
-
if (dcRouter.emailServer && dcRouter.emailServer.domainRegistry) {
|
|
67
|
-
emailDomains = dcRouter.emailServer.domainRegistry.getAllDomains();
|
|
68
|
-
} else if (
|
|
69
|
-
|
|
70
|
-
emailDomains = dcRouter.options.emailConfig.domains.map(d =>
|
|
86
|
+
if (dcRouter.emailServer && (dcRouter.emailServer as any).domainRegistry) {
|
|
87
|
+
emailDomains = (dcRouter.emailServer as any).domainRegistry.getAllDomains();
|
|
88
|
+
} else if (opts.emailConfig?.domains) {
|
|
89
|
+
emailDomains = opts.emailConfig.domains.map((d: any) =>
|
|
71
90
|
typeof d === 'string' ? d : d.domain
|
|
72
91
|
);
|
|
73
92
|
}
|
|
74
|
-
|
|
93
|
+
|
|
94
|
+
let portMapping: Record<string, number> | null = null;
|
|
95
|
+
if (opts.emailPortConfig?.portMapping) {
|
|
96
|
+
portMapping = {};
|
|
97
|
+
for (const [ext, int] of Object.entries(opts.emailPortConfig.portMapping)) {
|
|
98
|
+
portMapping[String(ext)] = int as number;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const email: interfaces.requests.IConfigData['email'] = {
|
|
103
|
+
enabled: !!dcRouter.emailServer,
|
|
104
|
+
ports: opts.emailConfig?.ports || [],
|
|
105
|
+
portMapping,
|
|
106
|
+
hostname: opts.emailConfig?.hostname || null,
|
|
107
|
+
domains: emailDomains,
|
|
108
|
+
emailRouteCount: opts.emailConfig?.routes?.length || 0,
|
|
109
|
+
receivedEmailsPath: opts.emailPortConfig?.receivedEmailsPath || null,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// --- DNS ---
|
|
113
|
+
const dnsRecords = (opts.dnsRecords || []).map(r => ({
|
|
114
|
+
name: r.name,
|
|
115
|
+
type: r.type,
|
|
116
|
+
value: r.value,
|
|
117
|
+
ttl: r.ttl,
|
|
118
|
+
}));
|
|
119
|
+
|
|
120
|
+
const dns: interfaces.requests.IConfigData['dns'] = {
|
|
121
|
+
enabled: !!dcRouter.dnsServer,
|
|
122
|
+
port: 53,
|
|
123
|
+
nsDomains: opts.dnsNsDomains || [],
|
|
124
|
+
scopes: opts.dnsScopes || [],
|
|
125
|
+
recordCount: dnsRecords.length,
|
|
126
|
+
records: dnsRecords,
|
|
127
|
+
dnsChallenge: !!opts.dnsChallenge?.cloudflareApiKey,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// --- TLS ---
|
|
131
|
+
let tlsSource: 'acme' | 'static' | 'none' = 'none';
|
|
132
|
+
if (opts.tls?.certPath && opts.tls?.keyPath) {
|
|
133
|
+
tlsSource = 'static';
|
|
134
|
+
} else if (opts.smartProxyConfig?.acme?.enabled !== false && opts.smartProxyConfig?.acme) {
|
|
135
|
+
tlsSource = 'acme';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const tls: interfaces.requests.IConfigData['tls'] = {
|
|
139
|
+
contactEmail: opts.tls?.contactEmail || opts.smartProxyConfig?.acme?.accountEmail || null,
|
|
140
|
+
domain: opts.tls?.domain || null,
|
|
141
|
+
source: tlsSource,
|
|
142
|
+
certPath: opts.tls?.certPath || null,
|
|
143
|
+
keyPath: opts.tls?.keyPath || null,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// --- Cache ---
|
|
147
|
+
const cacheConfig = opts.cacheConfig;
|
|
148
|
+
const cache: interfaces.requests.IConfigData['cache'] = {
|
|
149
|
+
enabled: cacheConfig?.enabled !== false,
|
|
150
|
+
storagePath: cacheConfig?.storagePath || resolvedPaths.defaultTsmDbPath,
|
|
151
|
+
dbName: cacheConfig?.dbName || 'dcrouter',
|
|
152
|
+
defaultTTLDays: cacheConfig?.defaultTTLDays || 30,
|
|
153
|
+
cleanupIntervalHours: cacheConfig?.cleanupIntervalHours || 1,
|
|
154
|
+
ttlConfig: cacheConfig?.ttlConfig ? { ...cacheConfig.ttlConfig } as Record<string, number> : {},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// --- RADIUS ---
|
|
158
|
+
const radiusCfg = opts.radiusConfig;
|
|
159
|
+
const radius: interfaces.requests.IConfigData['radius'] = {
|
|
160
|
+
enabled: !!dcRouter.radiusServer,
|
|
161
|
+
authPort: radiusCfg?.authPort || null,
|
|
162
|
+
acctPort: radiusCfg?.acctPort || null,
|
|
163
|
+
bindAddress: radiusCfg?.bindAddress || null,
|
|
164
|
+
clientCount: radiusCfg?.clients?.length || 0,
|
|
165
|
+
vlanDefaultVlan: radiusCfg?.vlanAssignment?.defaultVlan ?? null,
|
|
166
|
+
vlanAllowUnknownMacs: radiusCfg?.vlanAssignment?.allowUnknownMacs ?? null,
|
|
167
|
+
vlanMappingCount: radiusCfg?.vlanAssignment?.mappings?.length || 0,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// --- Remote Ingress ---
|
|
171
|
+
const riCfg = opts.remoteIngressConfig;
|
|
172
|
+
const remoteIngress: interfaces.requests.IConfigData['remoteIngress'] = {
|
|
173
|
+
enabled: !!dcRouter.remoteIngressManager,
|
|
174
|
+
tunnelPort: riCfg?.tunnelPort || null,
|
|
175
|
+
hubDomain: riCfg?.hubDomain || null,
|
|
176
|
+
tlsConfigured: !!(riCfg?.tls?.certPath && riCfg?.tls?.keyPath),
|
|
177
|
+
};
|
|
178
|
+
|
|
75
179
|
return {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
},
|
|
85
|
-
domains: emailDomains,
|
|
86
|
-
},
|
|
87
|
-
dns: {
|
|
88
|
-
enabled: !!dcRouter.dnsServer,
|
|
89
|
-
port: 53,
|
|
90
|
-
nameservers: dcRouter.options.dnsNsDomains || [],
|
|
91
|
-
caching: true,
|
|
92
|
-
ttl: 300,
|
|
93
|
-
},
|
|
94
|
-
proxy: {
|
|
95
|
-
enabled: !!dcRouter.smartProxy,
|
|
96
|
-
httpPort: 80,
|
|
97
|
-
httpsPort: 443,
|
|
98
|
-
maxConnections: 1000,
|
|
99
|
-
},
|
|
100
|
-
security: {
|
|
101
|
-
blockList: [],
|
|
102
|
-
rateLimit: true,
|
|
103
|
-
spamDetection: true,
|
|
104
|
-
tlsRequired: false,
|
|
105
|
-
},
|
|
180
|
+
system,
|
|
181
|
+
smartProxy,
|
|
182
|
+
email,
|
|
183
|
+
dns,
|
|
184
|
+
tls,
|
|
185
|
+
cache,
|
|
186
|
+
radius,
|
|
187
|
+
remoteIngress,
|
|
106
188
|
};
|
|
107
189
|
}
|
|
108
|
-
}
|
|
190
|
+
}
|
package/ts_web/appstate.ts
CHANGED
|
@@ -43,42 +43,52 @@ export class OpsDashboard extends DeesElement {
|
|
|
43
43
|
private viewTabs = [
|
|
44
44
|
{
|
|
45
45
|
name: 'Overview',
|
|
46
|
+
iconName: 'lucide:layoutDashboard',
|
|
46
47
|
element: OpsViewOverview,
|
|
47
48
|
},
|
|
49
|
+
{
|
|
50
|
+
name: 'Configuration',
|
|
51
|
+
iconName: 'lucide:settings',
|
|
52
|
+
element: OpsViewConfig,
|
|
53
|
+
},
|
|
48
54
|
{
|
|
49
55
|
name: 'Network',
|
|
56
|
+
iconName: 'lucide:network',
|
|
50
57
|
element: OpsViewNetwork,
|
|
51
58
|
},
|
|
52
59
|
{
|
|
53
60
|
name: 'Emails',
|
|
61
|
+
iconName: 'lucide:mail',
|
|
54
62
|
element: OpsViewEmails,
|
|
55
63
|
},
|
|
56
64
|
{
|
|
57
65
|
name: 'Logs',
|
|
66
|
+
iconName: 'lucide:scrollText',
|
|
58
67
|
element: OpsViewLogs,
|
|
59
68
|
},
|
|
60
69
|
{
|
|
61
70
|
name: 'Routes',
|
|
71
|
+
iconName: 'lucide:route',
|
|
62
72
|
element: OpsViewRoutes,
|
|
63
73
|
},
|
|
64
74
|
{
|
|
65
75
|
name: 'ApiTokens',
|
|
76
|
+
iconName: 'lucide:key',
|
|
66
77
|
element: OpsViewApiTokens,
|
|
67
78
|
},
|
|
68
|
-
{
|
|
69
|
-
name: 'Configuration',
|
|
70
|
-
element: OpsViewConfig,
|
|
71
|
-
},
|
|
72
79
|
{
|
|
73
80
|
name: 'Security',
|
|
81
|
+
iconName: 'lucide:shield',
|
|
74
82
|
element: OpsViewSecurity,
|
|
75
83
|
},
|
|
76
84
|
{
|
|
77
85
|
name: 'Certificates',
|
|
86
|
+
iconName: 'lucide:badgeCheck',
|
|
78
87
|
element: OpsViewCertificates,
|
|
79
88
|
},
|
|
80
89
|
{
|
|
81
90
|
name: 'RemoteIngress',
|
|
91
|
+
iconName: 'lucide:globe',
|
|
82
92
|
element: OpsViewRemoteIngress,
|
|
83
93
|
},
|
|
84
94
|
];
|
|
@@ -225,13 +225,17 @@ export class OpsViewApiTokens extends DeesElement {
|
|
|
225
225
|
name: 'Create',
|
|
226
226
|
iconName: 'lucide:key',
|
|
227
227
|
action: async (modalArg: any) => {
|
|
228
|
-
const
|
|
228
|
+
const contentEl = modalArg.shadowRoot?.querySelector('.content');
|
|
229
|
+
const form = contentEl?.querySelector('dees-form');
|
|
229
230
|
if (!form) return;
|
|
230
231
|
const formData = await form.collectFormData();
|
|
231
232
|
if (!formData.name) return;
|
|
232
233
|
|
|
233
|
-
// dees-input-tags
|
|
234
|
-
|
|
234
|
+
// dees-input-tags is not in dees-form's FORM_INPUT_TYPES, so collectFormData() won't
|
|
235
|
+
// include it. Query the tags input directly and call getValue().
|
|
236
|
+
const tagsInput = form.querySelector('dees-input-tags') as any;
|
|
237
|
+
const rawScopes: string[] = tagsInput?.getValue?.() || tagsInput?.value || formData.scopes || [];
|
|
238
|
+
const scopes = rawScopes
|
|
235
239
|
.filter((s: string) => allScopes.includes(s as any)) as TApiTokenScope[];
|
|
236
240
|
|
|
237
241
|
const expiresInDays = formData.expiresInDays
|