@nocobase/acl 2.2.0-alpha.7 → 2.2.0-alpha.9
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/lib/acl.d.ts +18 -0
- package/lib/acl.js +153 -71
- package/package.json +2 -2
package/lib/acl.d.ts
CHANGED
|
@@ -61,6 +61,22 @@ interface CanArgs {
|
|
|
61
61
|
ctx?: any;
|
|
62
62
|
roles?: string[];
|
|
63
63
|
}
|
|
64
|
+
export interface ResolveActionParamsOptions {
|
|
65
|
+
resourceName: string;
|
|
66
|
+
actionName: string;
|
|
67
|
+
rawResourceName?: string;
|
|
68
|
+
params?: any;
|
|
69
|
+
useCurrentRepository?: boolean;
|
|
70
|
+
}
|
|
71
|
+
export interface ResolvedActionParams {
|
|
72
|
+
actionName: string;
|
|
73
|
+
resourceName: string;
|
|
74
|
+
rawResourceName: string;
|
|
75
|
+
can: CanResult | null;
|
|
76
|
+
rawParams: any;
|
|
77
|
+
parsedParams?: any;
|
|
78
|
+
mergedParams: any;
|
|
79
|
+
}
|
|
64
80
|
export declare class ACL extends EventEmitter {
|
|
65
81
|
/**
|
|
66
82
|
* @internal
|
|
@@ -118,10 +134,12 @@ export declare class ACL extends EventEmitter {
|
|
|
118
134
|
* @internal
|
|
119
135
|
*/
|
|
120
136
|
getActionParams(ctx: any): Promise<void>;
|
|
137
|
+
resolveActionParams(ctx: any, options: ResolveActionParamsOptions): Promise<ResolvedActionParams>;
|
|
121
138
|
addGeneralFixedParams(merger: GeneralMerger): void;
|
|
122
139
|
addFixedParams(resource: string, action: string, merger: Merger): void;
|
|
123
140
|
registerSnippet(snippet: SnippetOptions): void;
|
|
124
141
|
protected addCoreMiddleware(): void;
|
|
142
|
+
private resolvePermissionParams;
|
|
125
143
|
protected isAvailableAction(actionName: string): boolean;
|
|
126
144
|
}
|
|
127
145
|
export declare function createUserProvider(options: {
|
package/lib/acl.js
CHANGED
|
@@ -288,16 +288,7 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
288
288
|
ctx.acl = acl;
|
|
289
289
|
const roleName = ctx.state.currentRole || "anonymous";
|
|
290
290
|
const { resourceName: rawResourceName, actionName } = ctx.action;
|
|
291
|
-
|
|
292
|
-
if (rawResourceName.includes(".")) {
|
|
293
|
-
resourceName = rawResourceName.split(".").pop();
|
|
294
|
-
}
|
|
295
|
-
if (ctx.getCurrentRepository) {
|
|
296
|
-
const currentRepository = ctx.getCurrentRepository();
|
|
297
|
-
if (currentRepository && currentRepository.targetCollection) {
|
|
298
|
-
resourceName = ctx.getCurrentRepository().targetCollection.name;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
291
|
+
const resourceName = resolveResourceName(ctx, rawResourceName, true);
|
|
301
292
|
ctx.can = (options) => {
|
|
302
293
|
const roles = ctx.state.currentRoles || [roleName];
|
|
303
294
|
const can = acl.can({ roles, ...options });
|
|
@@ -318,19 +309,9 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
318
309
|
* @internal
|
|
319
310
|
*/
|
|
320
311
|
async getActionParams(ctx) {
|
|
321
|
-
|
|
322
|
-
const roleNames = ((_a = ctx.state.currentRoles) == null ? void 0 : _a.length) ? ctx.state.currentRoles : "anonymous";
|
|
312
|
+
const roleNames = getRoleNames(ctx);
|
|
323
313
|
const { resourceName: rawResourceName, actionName } = ctx.action;
|
|
324
|
-
|
|
325
|
-
if (rawResourceName.includes(".")) {
|
|
326
|
-
resourceName = rawResourceName.split(".").pop();
|
|
327
|
-
}
|
|
328
|
-
if (ctx.getCurrentRepository) {
|
|
329
|
-
const currentRepository = ctx.getCurrentRepository();
|
|
330
|
-
if (currentRepository && currentRepository.targetCollection) {
|
|
331
|
-
resourceName = ctx.getCurrentRepository().targetCollection.name;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
314
|
+
const resourceName = resolveResourceName(ctx, rawResourceName, true);
|
|
334
315
|
ctx.can = (options) => {
|
|
335
316
|
const can = this.can({ roles: roleNames, ...options });
|
|
336
317
|
if (can) {
|
|
@@ -346,6 +327,25 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
346
327
|
await (0, import_koa_compose.default)(this.middlewares.nodes)(ctx, async () => {
|
|
347
328
|
});
|
|
348
329
|
}
|
|
330
|
+
async resolveActionParams(ctx, options) {
|
|
331
|
+
const rawResourceName = options.rawResourceName || options.resourceName;
|
|
332
|
+
const resourceName = resolveResourceName(ctx, options.resourceName, options.useCurrentRepository === true);
|
|
333
|
+
const roleNames = getRoleNames(ctx);
|
|
334
|
+
const can = this.can({
|
|
335
|
+
roles: roleNames,
|
|
336
|
+
resource: resourceName,
|
|
337
|
+
action: options.actionName,
|
|
338
|
+
rawResourceName
|
|
339
|
+
});
|
|
340
|
+
return this.resolvePermissionParams(ctx, {
|
|
341
|
+
actionName: options.actionName,
|
|
342
|
+
can,
|
|
343
|
+
params: options.params,
|
|
344
|
+
rawResourceName,
|
|
345
|
+
resourceName,
|
|
346
|
+
skip: false
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
349
|
addGeneralFixedParams(merger) {
|
|
350
350
|
this.fixedParamsManager.addGeneralParams(merger);
|
|
351
351
|
}
|
|
@@ -359,60 +359,25 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
359
359
|
const acl = this;
|
|
360
360
|
this.middlewares.add(
|
|
361
361
|
async (ctx, next) => {
|
|
362
|
-
var _a, _b
|
|
362
|
+
var _a, _b;
|
|
363
363
|
const resourcerAction = ctx.action;
|
|
364
364
|
const { resourceName, actionName } = ctx.permission;
|
|
365
365
|
const permission = ctx.permission;
|
|
366
366
|
((_a = ctx.log) == null ? void 0 : _a.debug) && ctx.log.debug("ctx permission", permission);
|
|
367
|
-
if ((!permission.can || typeof permission.can !== "object") && !permission.skip) {
|
|
368
|
-
ctx.throw(403, "No permissions");
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
const params = ((_b = permission.can) == null ? void 0 : _b.params) || acl.fixedParamsManager.getParams(resourceName, actionName);
|
|
372
|
-
((_c = ctx.log) == null ? void 0 : _c.debug) && ctx.log.debug("acl params", params);
|
|
373
367
|
try {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
ctx.permission.parsedParams = parsedParams;
|
|
388
|
-
((_f = ctx.log) == null ? void 0 : _f.debug) && ctx.log.debug("acl parsedParams", parsedParams);
|
|
389
|
-
ctx.permission.rawParams = import_lodash.default.cloneDeep(resourcerAction.params);
|
|
390
|
-
if (parsedParams.appends && resourcerAction.params.fields) {
|
|
391
|
-
for (const queryField of resourcerAction.params.fields) {
|
|
392
|
-
if (parsedParams.appends.indexOf(queryField) !== -1) {
|
|
393
|
-
if (!resourcerAction.params.appends) {
|
|
394
|
-
resourcerAction.params.appends = [];
|
|
395
|
-
}
|
|
396
|
-
resourcerAction.params.appends.push(queryField);
|
|
397
|
-
resourcerAction.params.fields = resourcerAction.params.fields.filter((f) => f !== queryField);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
const isEmptyFields = resourcerAction.params.fields && resourcerAction.params.fields.length === 0;
|
|
402
|
-
resourcerAction.mergeParams(parsedParams, {
|
|
403
|
-
appends: /* @__PURE__ */ __name((x, y) => {
|
|
404
|
-
if (!x) {
|
|
405
|
-
return [];
|
|
406
|
-
}
|
|
407
|
-
if (!y) {
|
|
408
|
-
return x;
|
|
409
|
-
}
|
|
410
|
-
return x.filter((i) => y.includes(i.split(".").shift()));
|
|
411
|
-
}, "appends")
|
|
412
|
-
});
|
|
413
|
-
if (isEmptyFields) {
|
|
414
|
-
resourcerAction.params.fields = [];
|
|
415
|
-
}
|
|
368
|
+
const result = await acl.resolvePermissionParams(ctx, {
|
|
369
|
+
actionName,
|
|
370
|
+
can: permission.can,
|
|
371
|
+
params: resourcerAction.params,
|
|
372
|
+
rawResourceName: ctx.action.resourceName,
|
|
373
|
+
resourceName,
|
|
374
|
+
skip: permission.skip
|
|
375
|
+
});
|
|
376
|
+
if (result.parsedParams && resourcerAction.mergeParams) {
|
|
377
|
+
ctx.permission.parsedParams = result.parsedParams;
|
|
378
|
+
((_b = ctx.log) == null ? void 0 : _b.debug) && ctx.log.debug("acl parsedParams", result.parsedParams);
|
|
379
|
+
ctx.permission.rawParams = result.rawParams;
|
|
380
|
+
resourcerAction.params = result.mergedParams;
|
|
416
381
|
ctx.permission.mergedParams = import_lodash.default.cloneDeep(resourcerAction.params);
|
|
417
382
|
}
|
|
418
383
|
} catch (e) {
|
|
@@ -430,12 +395,129 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
430
395
|
}
|
|
431
396
|
);
|
|
432
397
|
}
|
|
398
|
+
async resolvePermissionParams(ctx, options) {
|
|
399
|
+
var _a, _b, _c;
|
|
400
|
+
const { actionName, can, rawResourceName, resourceName } = options;
|
|
401
|
+
const rawParams = import_lodash.default.cloneDeep(options.params || {});
|
|
402
|
+
if ((!can || typeof can !== "object") && !options.skip) {
|
|
403
|
+
throw new import_no_permission_error.NoPermissionError("No permissions");
|
|
404
|
+
}
|
|
405
|
+
const params = (can == null ? void 0 : can.params) || this.fixedParamsManager.getParams(resourceName, actionName);
|
|
406
|
+
((_a = ctx.log) == null ? void 0 : _a.debug) && ctx.log.debug("acl params", params);
|
|
407
|
+
if (!params) {
|
|
408
|
+
return {
|
|
409
|
+
actionName,
|
|
410
|
+
can,
|
|
411
|
+
mergedParams: rawParams,
|
|
412
|
+
rawParams,
|
|
413
|
+
rawResourceName,
|
|
414
|
+
resourceName
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
const db = ctx.database ?? ctx.db;
|
|
418
|
+
const collection = (_b = db == null ? void 0 : db.getCollection) == null ? void 0 : _b.call(db, resourceName);
|
|
419
|
+
checkFilterParams(collection, params == null ? void 0 : params.filter);
|
|
420
|
+
const parsedFilter = await parseJsonTemplate(params.filter, {
|
|
421
|
+
state: ctx.state,
|
|
422
|
+
timezone: getTimezone(ctx),
|
|
423
|
+
userProvider: createUserProvider({
|
|
424
|
+
db: ctx.db,
|
|
425
|
+
currentUser: (_c = ctx.state) == null ? void 0 : _c.currentUser
|
|
426
|
+
})
|
|
427
|
+
});
|
|
428
|
+
const parsedParams = params.filter ? { ...params, filter: parsedFilter ?? params.filter } : params;
|
|
429
|
+
const mergedParams = mergeActionParams(rawParams, parsedParams);
|
|
430
|
+
return {
|
|
431
|
+
actionName,
|
|
432
|
+
can,
|
|
433
|
+
mergedParams,
|
|
434
|
+
parsedParams,
|
|
435
|
+
rawParams,
|
|
436
|
+
rawResourceName,
|
|
437
|
+
resourceName
|
|
438
|
+
};
|
|
439
|
+
}
|
|
433
440
|
isAvailableAction(actionName) {
|
|
434
441
|
return this.availableActions.has(this.resolveActionAlias(actionName));
|
|
435
442
|
}
|
|
436
443
|
};
|
|
437
444
|
__name(_ACL, "ACL");
|
|
438
445
|
let ACL = _ACL;
|
|
446
|
+
function getRoleNames(ctx) {
|
|
447
|
+
var _a;
|
|
448
|
+
if ((_a = ctx.state.currentRoles) == null ? void 0 : _a.length) {
|
|
449
|
+
return ctx.state.currentRoles;
|
|
450
|
+
}
|
|
451
|
+
return [ctx.state.currentRole || "anonymous"];
|
|
452
|
+
}
|
|
453
|
+
__name(getRoleNames, "getRoleNames");
|
|
454
|
+
function resolveResourceName(ctx, rawResourceName, useCurrentRepository) {
|
|
455
|
+
const repository = resolveResourceRepository(ctx, rawResourceName, useCurrentRepository);
|
|
456
|
+
const collection = (repository == null ? void 0 : repository.targetCollection) || (repository == null ? void 0 : repository.collection);
|
|
457
|
+
if (collection == null ? void 0 : collection.name) {
|
|
458
|
+
return collection.name;
|
|
459
|
+
}
|
|
460
|
+
return rawResourceName.includes(".") ? rawResourceName.split(".").pop() : rawResourceName;
|
|
461
|
+
}
|
|
462
|
+
__name(resolveResourceName, "resolveResourceName");
|
|
463
|
+
function resolveResourceRepository(ctx, resourceName, useCurrentRepository) {
|
|
464
|
+
var _a, _b, _c;
|
|
465
|
+
if (useCurrentRepository && ctx.getCurrentRepository) {
|
|
466
|
+
return ctx.getCurrentRepository();
|
|
467
|
+
}
|
|
468
|
+
const collectionManager = (_a = ctx.dataSource) == null ? void 0 : _a.collectionManager;
|
|
469
|
+
if (collectionManager == null ? void 0 : collectionManager.getRepository) {
|
|
470
|
+
try {
|
|
471
|
+
return collectionManager.getRepository(resourceName, (_b = ctx.action) == null ? void 0 : _b.sourceId);
|
|
472
|
+
} catch (error) {
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const db = ctx.database ?? ctx.db;
|
|
476
|
+
if (db == null ? void 0 : db.getRepository) {
|
|
477
|
+
try {
|
|
478
|
+
return db.getRepository(resourceName, (_c = ctx.action) == null ? void 0 : _c.sourceId);
|
|
479
|
+
} catch (error) {
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
__name(resolveResourceRepository, "resolveResourceRepository");
|
|
484
|
+
function mergeActionParams(rawParams, parsedParams) {
|
|
485
|
+
const mergedParams = import_lodash.default.cloneDeep(rawParams || {});
|
|
486
|
+
if (parsedParams.appends && mergedParams.fields) {
|
|
487
|
+
for (const queryField of mergedParams.fields) {
|
|
488
|
+
if (parsedParams.appends.indexOf(queryField) !== -1) {
|
|
489
|
+
if (!mergedParams.appends) {
|
|
490
|
+
mergedParams.appends = [];
|
|
491
|
+
}
|
|
492
|
+
mergedParams.appends.push(queryField);
|
|
493
|
+
mergedParams.fields = mergedParams.fields.filter((f) => f !== queryField);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
const isEmptyFields = mergedParams.fields && mergedParams.fields.length === 0;
|
|
498
|
+
(0, import_utils.assign)(mergedParams, parsedParams, {
|
|
499
|
+
appends: /* @__PURE__ */ __name((x, y) => {
|
|
500
|
+
if (!x) {
|
|
501
|
+
return [];
|
|
502
|
+
}
|
|
503
|
+
if (!y) {
|
|
504
|
+
return x;
|
|
505
|
+
}
|
|
506
|
+
return x.filter((i) => y.includes(i.split(".").shift()));
|
|
507
|
+
}, "appends"),
|
|
508
|
+
blacklist: "intersect",
|
|
509
|
+
except: "union",
|
|
510
|
+
fields: "intersect",
|
|
511
|
+
filter: "andMerge",
|
|
512
|
+
sort: "overwrite",
|
|
513
|
+
whitelist: "intersect"
|
|
514
|
+
});
|
|
515
|
+
if (isEmptyFields) {
|
|
516
|
+
mergedParams.fields = [];
|
|
517
|
+
}
|
|
518
|
+
return mergedParams;
|
|
519
|
+
}
|
|
520
|
+
__name(mergeActionParams, "mergeActionParams");
|
|
439
521
|
function getTimezone(ctx) {
|
|
440
522
|
var _a, _b, _c, _d, _e, _f;
|
|
441
523
|
return ((_b = (_a = ctx == null ? void 0 : ctx.request) == null ? void 0 : _a.get) == null ? void 0 : _b.call(_a, "x-timezone")) ?? ((_d = (_c = ctx == null ? void 0 : ctx.request) == null ? void 0 : _c.header) == null ? void 0 : _d["x-timezone"]) ?? ((_f = (_e = ctx == null ? void 0 : ctx.req) == null ? void 0 : _e.headers) == null ? void 0 : _f["x-timezone"]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/acl",
|
|
3
|
-
"version": "2.2.0-alpha.
|
|
3
|
+
"version": "2.2.0-alpha.9",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -18,5 +18,5 @@
|
|
|
18
18
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
19
19
|
"directory": "packages/acl"
|
|
20
20
|
},
|
|
21
|
-
"gitHead": "
|
|
21
|
+
"gitHead": "4949bf5ebcd92d77a3a0a718ed578c270e4bd570"
|
|
22
22
|
}
|