@serve.zone/dcrouter 13.31.0 → 13.32.1
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 +721 -721
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/config/classes.route-config-manager.d.ts +1 -0
- package/dist_ts/config/classes.route-config-manager.js +28 -3
- package/dist_ts/config/classes.target-profile-manager.d.ts +1 -0
- package/dist_ts/config/classes.target-profile-manager.js +11 -8
- package/dist_ts/opsserver/classes.opsserver.d.ts +4 -2
- package/dist_ts/opsserver/classes.opsserver.js +2 -11
- package/dist_ts/opsserver/handlers/acme-config.handler.js +7 -24
- package/dist_ts/opsserver/handlers/admin.handler.d.ts +3 -1
- package/dist_ts/opsserver/handlers/admin.handler.js +95 -110
- package/dist_ts/opsserver/handlers/api-token.handler.js +28 -2
- package/dist_ts/opsserver/handlers/certificate.handler.js +7 -24
- package/dist_ts/opsserver/handlers/config.handler.js +3 -1
- package/dist_ts/opsserver/handlers/dns-provider.handler.js +7 -24
- package/dist_ts/opsserver/handlers/dns-record.handler.js +7 -24
- package/dist_ts/opsserver/handlers/domain.handler.js +7 -24
- package/dist_ts/opsserver/handlers/email-domain.handler.js +7 -24
- package/dist_ts/opsserver/handlers/email-ops.handler.js +8 -1
- package/dist_ts/opsserver/handlers/logs.handler.js +4 -1
- package/dist_ts/opsserver/handlers/network-target.handler.js +7 -24
- package/dist_ts/opsserver/handlers/radius.handler.js +32 -1
- package/dist_ts/opsserver/handlers/remoteingress.handler.js +24 -1
- package/dist_ts/opsserver/handlers/route-management.handler.js +7 -26
- package/dist_ts/opsserver/handlers/security.handler.js +32 -7
- package/dist_ts/opsserver/handlers/source-profile.handler.js +7 -24
- package/dist_ts/opsserver/handlers/stats.handler.js +8 -1
- package/dist_ts/opsserver/handlers/target-profile.handler.js +7 -24
- package/dist_ts/opsserver/handlers/users.handler.js +33 -13
- package/dist_ts/opsserver/handlers/vpn.handler.js +34 -1
- package/dist_ts/opsserver/handlers/workhoster.handler.js +16 -35
- package/dist_ts/opsserver/helpers/auth.d.ts +21 -0
- package/dist_ts/opsserver/helpers/auth.js +63 -0
- package/dist_ts_interfaces/data/route-management.d.ts +2 -1
- package/dist_ts_interfaces/data/route-management.js +48 -2
- package/dist_ts_interfaces/requests/api-tokens.d.ts +10 -5
- package/dist_ts_interfaces/requests/combined.stats.d.ts +2 -1
- package/dist_ts_interfaces/requests/config.d.ts +2 -1
- package/dist_ts_interfaces/requests/email-ops.d.ts +6 -3
- package/dist_ts_interfaces/requests/logs.d.ts +4 -2
- package/dist_ts_interfaces/requests/radius.d.ts +24 -12
- package/dist_ts_interfaces/requests/remoteingress.d.ts +14 -7
- package/dist_ts_interfaces/requests/security-policy.d.ts +16 -8
- package/dist_ts_interfaces/requests/stats.d.ts +18 -9
- package/dist_ts_interfaces/requests/users.d.ts +6 -3
- package/dist_ts_interfaces/requests/vpn.d.ts +22 -11
- package/dist_ts_interfaces/requests/workhoster.d.ts +10 -5
- package/dist_ts_migrations/index.js +3 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/access/ops-view-apitokens.js +2 -21
- package/package.json +4 -4
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/config/classes.route-config-manager.ts +35 -2
- package/ts/config/classes.target-profile-manager.ts +10 -7
- package/ts/opsserver/classes.opsserver.ts +3 -14
- package/ts/opsserver/handlers/acme-config.handler.ts +6 -23
- package/ts/opsserver/handlers/admin.handler.ts +109 -123
- package/ts/opsserver/handlers/api-token.handler.ts +27 -1
- package/ts/opsserver/handlers/certificate.handler.ts +6 -23
- package/ts/opsserver/handlers/config.handler.ts +2 -0
- package/ts/opsserver/handlers/dns-provider.handler.ts +6 -23
- package/ts/opsserver/handlers/dns-record.handler.ts +6 -23
- package/ts/opsserver/handlers/domain.handler.ts +6 -23
- package/ts/opsserver/handlers/email-domain.handler.ts +6 -23
- package/ts/opsserver/handlers/email-ops.handler.ts +7 -0
- package/ts/opsserver/handlers/logs.handler.ts +3 -0
- package/ts/opsserver/handlers/network-target.handler.ts +6 -23
- package/ts/opsserver/handlers/radius.handler.ts +31 -0
- package/ts/opsserver/handlers/remoteingress.handler.ts +23 -0
- package/ts/opsserver/handlers/route-management.handler.ts +6 -25
- package/ts/opsserver/handlers/security.handler.ts +31 -6
- package/ts/opsserver/handlers/source-profile.handler.ts +6 -23
- package/ts/opsserver/handlers/stats.handler.ts +7 -0
- package/ts/opsserver/handlers/target-profile.handler.ts +6 -23
- package/ts/opsserver/handlers/users.handler.ts +32 -12
- package/ts/opsserver/handlers/vpn.handler.ts +33 -0
- package/ts/opsserver/handlers/workhoster.handler.ts +18 -33
- package/ts/opsserver/helpers/auth.ts +91 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/access/ops-view-apitokens.ts +1 -20
|
@@ -4,6 +4,7 @@ import * as interfaces from '../../../ts_interfaces/index.js';
|
|
|
4
4
|
import { MetricsManager } from '../../monitoring/index.js';
|
|
5
5
|
import { SecurityLogger } from '../../security/classes.securitylogger.js';
|
|
6
6
|
import { commitinfo } from '../../00_commitinfo_data.js';
|
|
7
|
+
import { requireOpsAuth } from '../helpers/auth.js';
|
|
7
8
|
|
|
8
9
|
export class StatsHandler {
|
|
9
10
|
constructor(private opsServerRef: OpsServer) {
|
|
@@ -19,6 +20,7 @@ export class StatsHandler {
|
|
|
19
20
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServerStatistics>(
|
|
20
21
|
'getServerStatistics',
|
|
21
22
|
async (dataArg, toolsArg) => {
|
|
23
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'stats:read' });
|
|
22
24
|
const stats = await this.collectServerStats();
|
|
23
25
|
return {
|
|
24
26
|
stats: {
|
|
@@ -42,6 +44,7 @@ export class StatsHandler {
|
|
|
42
44
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetEmailStatistics>(
|
|
43
45
|
'getEmailStatistics',
|
|
44
46
|
async (dataArg, toolsArg) => {
|
|
47
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'stats:read' });
|
|
45
48
|
const emailServer = this.opsServerRef.dcRouterRef.emailServer;
|
|
46
49
|
if (!emailServer) {
|
|
47
50
|
return {
|
|
@@ -81,6 +84,7 @@ export class StatsHandler {
|
|
|
81
84
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetDnsStatistics>(
|
|
82
85
|
'getDnsStatistics',
|
|
83
86
|
async (dataArg, toolsArg) => {
|
|
87
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'stats:read' });
|
|
84
88
|
const dnsServer = this.opsServerRef.dcRouterRef.dnsServer;
|
|
85
89
|
if (!dnsServer) {
|
|
86
90
|
return {
|
|
@@ -118,6 +122,7 @@ export class StatsHandler {
|
|
|
118
122
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetQueueStatus>(
|
|
119
123
|
'getQueueStatus',
|
|
120
124
|
async (dataArg, toolsArg) => {
|
|
125
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'stats:read' });
|
|
121
126
|
const emailServer = this.opsServerRef.dcRouterRef.emailServer;
|
|
122
127
|
const queues: interfaces.data.IQueueStatus[] = [];
|
|
123
128
|
|
|
@@ -146,6 +151,7 @@ export class StatsHandler {
|
|
|
146
151
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetHealthStatus>(
|
|
147
152
|
'getHealthStatus',
|
|
148
153
|
async (dataArg, toolsArg) => {
|
|
154
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'stats:read' });
|
|
149
155
|
const health = await this.checkHealthStatus();
|
|
150
156
|
return {
|
|
151
157
|
health: {
|
|
@@ -171,6 +177,7 @@ export class StatsHandler {
|
|
|
171
177
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetCombinedMetrics>(
|
|
172
178
|
'getCombinedMetrics',
|
|
173
179
|
async (dataArg, toolsArg) => {
|
|
180
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'stats:read' });
|
|
174
181
|
const sections = dataArg.sections || {
|
|
175
182
|
server: true,
|
|
176
183
|
email: true,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
3
|
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
4
|
+
import { requireOpsAuth } from '../helpers/auth.js';
|
|
4
5
|
|
|
5
6
|
export class TargetProfileHandler {
|
|
6
7
|
public typedrouter = new plugins.typedrequest.TypedRouter();
|
|
@@ -14,29 +15,11 @@ export class TargetProfileHandler {
|
|
|
14
15
|
request: { identity?: interfaces.data.IIdentity; apiToken?: string },
|
|
15
16
|
requiredScope?: interfaces.data.TApiTokenScope,
|
|
16
17
|
): Promise<string> {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (isAdmin) return request.identity.userId;
|
|
23
|
-
} catch { /* fall through */ }
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (request.apiToken) {
|
|
27
|
-
const tokenManager = this.opsServerRef.dcRouterRef.apiTokenManager;
|
|
28
|
-
if (tokenManager) {
|
|
29
|
-
const token = await tokenManager.validateToken(request.apiToken);
|
|
30
|
-
if (token) {
|
|
31
|
-
if (!requiredScope || tokenManager.hasScope(token, requiredScope)) {
|
|
32
|
-
return token.createdBy;
|
|
33
|
-
}
|
|
34
|
-
throw new plugins.typedrequest.TypedResponseError('insufficient scope');
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
throw new plugins.typedrequest.TypedResponseError('unauthorized');
|
|
18
|
+
const auth = await requireOpsAuth(this.opsServerRef, request, {
|
|
19
|
+
scope: requiredScope,
|
|
20
|
+
requireAdminIdentity: requiredScope?.endsWith(':write'),
|
|
21
|
+
});
|
|
22
|
+
return auth.userId;
|
|
40
23
|
}
|
|
41
24
|
|
|
42
25
|
private registerHandlers(): void {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
3
|
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
4
|
+
import { requireOpsAuth } from '../helpers/auth.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Handler for OpsServer user accounts. Registers on adminRouter,
|
|
@@ -20,7 +21,12 @@ export class UsersHandler {
|
|
|
20
21
|
router.addTypedHandler(
|
|
21
22
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ListUsers>(
|
|
22
23
|
'listUsers',
|
|
23
|
-
async (
|
|
24
|
+
async (dataArg) => {
|
|
25
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
26
|
+
scope: 'users:read',
|
|
27
|
+
requireAdminIdentity: true,
|
|
28
|
+
requireAdminToken: true,
|
|
29
|
+
});
|
|
24
30
|
const users = await this.opsServerRef.adminHandler.listUsers();
|
|
25
31
|
return { users };
|
|
26
32
|
},
|
|
@@ -30,23 +36,37 @@ export class UsersHandler {
|
|
|
30
36
|
router.addTypedHandler(
|
|
31
37
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateUser>(
|
|
32
38
|
'createUser',
|
|
33
|
-
async (dataArg) =>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
async (dataArg) => {
|
|
40
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
41
|
+
scope: 'users:manage',
|
|
42
|
+
requireAdminIdentity: true,
|
|
43
|
+
requireAdminToken: true,
|
|
44
|
+
});
|
|
45
|
+
return this.opsServerRef.adminHandler.createUser({
|
|
46
|
+
email: dataArg.email,
|
|
47
|
+
name: dataArg.name,
|
|
48
|
+
role: dataArg.role,
|
|
49
|
+
password: dataArg.password,
|
|
50
|
+
enableIdpGlobalAuth: dataArg.enableIdpGlobalAuth,
|
|
51
|
+
});
|
|
52
|
+
},
|
|
40
53
|
),
|
|
41
54
|
);
|
|
42
55
|
|
|
43
56
|
router.addTypedHandler(
|
|
44
57
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteUser>(
|
|
45
58
|
'deleteUser',
|
|
46
|
-
async (dataArg) =>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
async (dataArg) => {
|
|
60
|
+
const auth = await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
61
|
+
scope: 'users:manage',
|
|
62
|
+
requireAdminIdentity: true,
|
|
63
|
+
requireAdminToken: true,
|
|
64
|
+
});
|
|
65
|
+
return this.opsServerRef.adminHandler.deleteUser({
|
|
66
|
+
id: dataArg.id,
|
|
67
|
+
requestingUserId: auth.userId,
|
|
68
|
+
});
|
|
69
|
+
},
|
|
50
70
|
),
|
|
51
71
|
);
|
|
52
72
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
3
|
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
4
|
+
import { requireOpsAuth } from '../helpers/auth.js';
|
|
4
5
|
|
|
5
6
|
export class VpnHandler {
|
|
6
7
|
constructor(private opsServerRef: OpsServer) {
|
|
@@ -18,6 +19,7 @@ export class VpnHandler {
|
|
|
18
19
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnClients>(
|
|
19
20
|
'getVpnClients',
|
|
20
21
|
async (dataArg, toolsArg) => {
|
|
22
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'vpn:read' });
|
|
21
23
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
22
24
|
if (!manager) {
|
|
23
25
|
return { clients: [] };
|
|
@@ -49,6 +51,7 @@ export class VpnHandler {
|
|
|
49
51
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnStatus>(
|
|
50
52
|
'getVpnStatus',
|
|
51
53
|
async (dataArg, toolsArg) => {
|
|
54
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'vpn:read' });
|
|
52
55
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
53
56
|
const vpnConfig = this.opsServerRef.dcRouterRef.options.vpnConfig;
|
|
54
57
|
if (!manager) {
|
|
@@ -84,6 +87,7 @@ export class VpnHandler {
|
|
|
84
87
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnConnectedClients>(
|
|
85
88
|
'getVpnConnectedClients',
|
|
86
89
|
async (dataArg, toolsArg) => {
|
|
90
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'vpn:read' });
|
|
87
91
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
88
92
|
if (!manager) {
|
|
89
93
|
return { connectedClients: [] };
|
|
@@ -111,6 +115,10 @@ export class VpnHandler {
|
|
|
111
115
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateVpnClient>(
|
|
112
116
|
'createVpnClient',
|
|
113
117
|
async (dataArg, toolsArg) => {
|
|
118
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
119
|
+
scope: 'vpn:write',
|
|
120
|
+
requireAdminIdentity: true,
|
|
121
|
+
});
|
|
114
122
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
115
123
|
if (!manager) {
|
|
116
124
|
return { success: false, message: 'VPN not configured' };
|
|
@@ -168,6 +176,10 @@ export class VpnHandler {
|
|
|
168
176
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateVpnClient>(
|
|
169
177
|
'updateVpnClient',
|
|
170
178
|
async (dataArg, toolsArg) => {
|
|
179
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
180
|
+
scope: 'vpn:write',
|
|
181
|
+
requireAdminIdentity: true,
|
|
182
|
+
});
|
|
171
183
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
172
184
|
if (!manager) {
|
|
173
185
|
return { success: false, message: 'VPN not configured' };
|
|
@@ -198,6 +210,10 @@ export class VpnHandler {
|
|
|
198
210
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteVpnClient>(
|
|
199
211
|
'deleteVpnClient',
|
|
200
212
|
async (dataArg, toolsArg) => {
|
|
213
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
214
|
+
scope: 'vpn:write',
|
|
215
|
+
requireAdminIdentity: true,
|
|
216
|
+
});
|
|
201
217
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
202
218
|
if (!manager) {
|
|
203
219
|
return { success: false, message: 'VPN not configured' };
|
|
@@ -218,6 +234,10 @@ export class VpnHandler {
|
|
|
218
234
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_EnableVpnClient>(
|
|
219
235
|
'enableVpnClient',
|
|
220
236
|
async (dataArg, toolsArg) => {
|
|
237
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
238
|
+
scope: 'vpn:write',
|
|
239
|
+
requireAdminIdentity: true,
|
|
240
|
+
});
|
|
221
241
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
222
242
|
if (!manager) {
|
|
223
243
|
return { success: false, message: 'VPN not configured' };
|
|
@@ -238,6 +258,10 @@ export class VpnHandler {
|
|
|
238
258
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DisableVpnClient>(
|
|
239
259
|
'disableVpnClient',
|
|
240
260
|
async (dataArg, toolsArg) => {
|
|
261
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
262
|
+
scope: 'vpn:write',
|
|
263
|
+
requireAdminIdentity: true,
|
|
264
|
+
});
|
|
241
265
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
242
266
|
if (!manager) {
|
|
243
267
|
return { success: false, message: 'VPN not configured' };
|
|
@@ -258,6 +282,10 @@ export class VpnHandler {
|
|
|
258
282
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RotateVpnClientKey>(
|
|
259
283
|
'rotateVpnClientKey',
|
|
260
284
|
async (dataArg, toolsArg) => {
|
|
285
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
286
|
+
scope: 'vpn:write',
|
|
287
|
+
requireAdminIdentity: true,
|
|
288
|
+
});
|
|
261
289
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
262
290
|
if (!manager) {
|
|
263
291
|
return { success: false, message: 'VPN not configured' };
|
|
@@ -281,6 +309,10 @@ export class VpnHandler {
|
|
|
281
309
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ExportVpnClientConfig>(
|
|
282
310
|
'exportVpnClientConfig',
|
|
283
311
|
async (dataArg, toolsArg) => {
|
|
312
|
+
await requireOpsAuth(this.opsServerRef, dataArg, {
|
|
313
|
+
scope: 'vpn:write',
|
|
314
|
+
requireAdminIdentity: true,
|
|
315
|
+
});
|
|
284
316
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
285
317
|
if (!manager) {
|
|
286
318
|
return { success: false, message: 'VPN not configured' };
|
|
@@ -301,6 +333,7 @@ export class VpnHandler {
|
|
|
301
333
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnClientTelemetry>(
|
|
302
334
|
'getVpnClientTelemetry',
|
|
303
335
|
async (dataArg, toolsArg) => {
|
|
336
|
+
await requireOpsAuth(this.opsServerRef, dataArg, { scope: 'vpn:read' });
|
|
304
337
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
305
338
|
if (!manager) {
|
|
306
339
|
return { success: false, message: 'VPN not configured' };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
3
|
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
4
|
+
import { requireOpsAuth } from '../helpers/auth.js';
|
|
4
5
|
|
|
5
6
|
type TAuthContext = {
|
|
6
7
|
userId: string;
|
|
@@ -20,39 +21,23 @@ export class WorkHosterHandler {
|
|
|
20
21
|
request: { identity?: interfaces.data.IIdentity; apiToken?: string },
|
|
21
22
|
requiredScope?: interfaces.data.TApiTokenScope,
|
|
22
23
|
): Promise<TAuthContext> {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (isAdmin) return { userId: request.identity.userId, isAdmin: true };
|
|
29
|
-
} catch { /* fall through */ }
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (request.apiToken) {
|
|
33
|
-
const tokenManager = this.opsServerRef.dcRouterRef.apiTokenManager;
|
|
34
|
-
if (tokenManager) {
|
|
35
|
-
const token = await tokenManager.validateToken(request.apiToken);
|
|
36
|
-
if (token) {
|
|
37
|
-
if (!requiredScope || tokenManager.hasScope(token, requiredScope)) {
|
|
38
|
-
return { userId: token.createdBy, isAdmin: token.policy?.role === 'admin', token };
|
|
39
|
-
}
|
|
40
|
-
throw new plugins.typedrequest.TypedResponseError('insufficient scope');
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
throw new plugins.typedrequest.TypedResponseError('unauthorized');
|
|
24
|
+
const auth = await requireOpsAuth(this.opsServerRef, request, {
|
|
25
|
+
scope: requiredScope,
|
|
26
|
+
requireAdminIdentity: requiredScope?.endsWith(':write'),
|
|
27
|
+
});
|
|
28
|
+
return { userId: auth.userId, isAdmin: auth.isAdmin, token: auth.token };
|
|
46
29
|
}
|
|
47
30
|
|
|
48
|
-
private async requireAdmin(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
31
|
+
private async requireAdmin(
|
|
32
|
+
request: { identity?: interfaces.data.IIdentity; apiToken?: string },
|
|
33
|
+
scope: interfaces.data.TApiTokenScope = 'gateway-clients:write',
|
|
34
|
+
): Promise<string> {
|
|
35
|
+
const auth = await requireOpsAuth(this.opsServerRef, request, {
|
|
36
|
+
scope,
|
|
37
|
+
requireAdminIdentity: true,
|
|
38
|
+
requireAdminToken: true,
|
|
39
|
+
});
|
|
40
|
+
return auth.userId;
|
|
56
41
|
}
|
|
57
42
|
|
|
58
43
|
private registerHandlers(): void {
|
|
@@ -83,7 +68,7 @@ export class WorkHosterHandler {
|
|
|
83
68
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ListGatewayClients>(
|
|
84
69
|
'listGatewayClients',
|
|
85
70
|
async (dataArg) => {
|
|
86
|
-
await this.requireAdmin(dataArg);
|
|
71
|
+
await this.requireAdmin(dataArg, 'gateway-clients:read');
|
|
87
72
|
return { gatewayClients: await this.listManagedGatewayClients() };
|
|
88
73
|
},
|
|
89
74
|
),
|
|
@@ -154,7 +139,7 @@ export class WorkHosterHandler {
|
|
|
154
139
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateGatewayClientToken>(
|
|
155
140
|
'createGatewayClientToken',
|
|
156
141
|
async (dataArg) => {
|
|
157
|
-
const userId = await this.requireAdmin(dataArg);
|
|
142
|
+
const userId = await this.requireAdmin(dataArg, 'tokens:manage');
|
|
158
143
|
const gatewayClient = await this.opsServerRef.dcRouterRef.gatewayClientManager?.getClient(dataArg.gatewayClientId);
|
|
159
144
|
const tokenManager = this.opsServerRef.dcRouterRef.apiTokenManager;
|
|
160
145
|
if (!gatewayClient || !gatewayClient.enabled) {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import type { OpsServer } from '../classes.opsserver.js';
|
|
3
|
+
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
4
|
+
|
|
5
|
+
export interface IAuthRequest {
|
|
6
|
+
identity?: interfaces.data.IIdentity;
|
|
7
|
+
apiToken?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface IAuthRequirement {
|
|
11
|
+
scope?: interfaces.data.TApiTokenScope;
|
|
12
|
+
requireAdminIdentity?: boolean;
|
|
13
|
+
requireAdminToken?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface IAuthContext {
|
|
17
|
+
type: 'identity' | 'apiToken';
|
|
18
|
+
userId: string;
|
|
19
|
+
role?: string;
|
|
20
|
+
isAdmin: boolean;
|
|
21
|
+
scopes: interfaces.data.TApiTokenScope[];
|
|
22
|
+
identity?: interfaces.data.IIdentity;
|
|
23
|
+
token?: interfaces.data.IStoredApiToken;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const typedAuthError = (messageArg: string) => {
|
|
27
|
+
return new plugins.typedrequest.TypedResponseError(messageArg);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export async function requireOpsAuth(
|
|
31
|
+
opsServerRefArg: OpsServer,
|
|
32
|
+
requestArg: IAuthRequest,
|
|
33
|
+
requirementArg: IAuthRequirement = {},
|
|
34
|
+
): Promise<IAuthContext> {
|
|
35
|
+
let identityNeedsAdmin = false;
|
|
36
|
+
let tokenNeedsAdmin = false;
|
|
37
|
+
let tokenNeedsScope = false;
|
|
38
|
+
|
|
39
|
+
if (requestArg.identity?.jwt) {
|
|
40
|
+
const identity = await opsServerRefArg.adminHandler.validateIdentity(requestArg.identity);
|
|
41
|
+
if (identity) {
|
|
42
|
+
const isAdmin = identity.role === 'admin';
|
|
43
|
+
if (!requirementArg.requireAdminIdentity || isAdmin) {
|
|
44
|
+
return {
|
|
45
|
+
type: 'identity',
|
|
46
|
+
userId: identity.userId,
|
|
47
|
+
role: identity.role,
|
|
48
|
+
isAdmin,
|
|
49
|
+
scopes: [],
|
|
50
|
+
identity,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
identityNeedsAdmin = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (requestArg.apiToken) {
|
|
58
|
+
const tokenManager = opsServerRefArg.dcRouterRef.apiTokenManager;
|
|
59
|
+
const token = tokenManager ? await tokenManager.validateToken(requestArg.apiToken) : null;
|
|
60
|
+
if (token) {
|
|
61
|
+
if (requirementArg.requireAdminToken && token.policy?.role !== 'admin') {
|
|
62
|
+
tokenNeedsAdmin = true;
|
|
63
|
+
} else if (requirementArg.scope && !tokenManager!.hasScope(token, requirementArg.scope)) {
|
|
64
|
+
tokenNeedsScope = true;
|
|
65
|
+
} else {
|
|
66
|
+
const scopes = token.policy?.role === 'admin'
|
|
67
|
+
? ['*' as interfaces.data.TApiTokenScope]
|
|
68
|
+
: Array.from(new Set([...(token.scopes || []), ...(token.policy?.scopes || [])]));
|
|
69
|
+
return {
|
|
70
|
+
type: 'apiToken',
|
|
71
|
+
userId: token.createdBy,
|
|
72
|
+
role: token.policy?.role || 'operator',
|
|
73
|
+
isAdmin: token.policy?.role === 'admin',
|
|
74
|
+
scopes,
|
|
75
|
+
token,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (tokenNeedsScope) {
|
|
82
|
+
throw typedAuthError('insufficient scope');
|
|
83
|
+
}
|
|
84
|
+
if (tokenNeedsAdmin) {
|
|
85
|
+
throw typedAuthError('admin API token required');
|
|
86
|
+
}
|
|
87
|
+
if (identityNeedsAdmin) {
|
|
88
|
+
throw typedAuthError('admin identity required');
|
|
89
|
+
}
|
|
90
|
+
throw typedAuthError('unauthorized');
|
|
91
|
+
}
|
|
@@ -200,26 +200,7 @@ export class OpsViewApiTokens extends DeesElement {
|
|
|
200
200
|
private async showCreateTokenDialog() {
|
|
201
201
|
const { DeesModal } = await import('@design.estate/dees-catalog');
|
|
202
202
|
|
|
203
|
-
const allScopes = [
|
|
204
|
-
'*',
|
|
205
|
-
'routes:read',
|
|
206
|
-
'routes:write',
|
|
207
|
-
'config:read',
|
|
208
|
-
'certificates:read',
|
|
209
|
-
'certificates:write',
|
|
210
|
-
'tokens:read',
|
|
211
|
-
'tokens:manage',
|
|
212
|
-
'domains:read',
|
|
213
|
-
'domains:write',
|
|
214
|
-
'dns-records:read',
|
|
215
|
-
'dns-records:write',
|
|
216
|
-
'email-domains:read',
|
|
217
|
-
'email-domains:write',
|
|
218
|
-
'gateway-clients:read',
|
|
219
|
-
'gateway-clients:write',
|
|
220
|
-
'workhosters:read',
|
|
221
|
-
'workhosters:write',
|
|
222
|
-
];
|
|
203
|
+
const allScopes = [...interfaces.data.apiTokenScopes];
|
|
223
204
|
|
|
224
205
|
await DeesModal.createAndShow({
|
|
225
206
|
heading: 'Create API Token',
|