@nocobase/acl 1.9.47 → 1.9.49
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 +22 -8
- package/lib/acl.js +99 -72
- package/package.json +4 -4
package/lib/acl.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { ACLRole, ResourceActionsOptions, RoleActionParams } from './acl-role';
|
|
|
15
15
|
import { AllowManager, ConditionFunc } from './allow-manager';
|
|
16
16
|
import FixedParamsManager, { Merger } from './fixed-params-manager';
|
|
17
17
|
import SnippetManager, { SnippetOptions } from './snippet-manager';
|
|
18
|
+
import Database, { Collection } from '@nocobase/database';
|
|
18
19
|
export interface CanResult {
|
|
19
20
|
role: string;
|
|
20
21
|
resource: string;
|
|
@@ -44,6 +45,14 @@ export interface ListenerContext {
|
|
|
44
45
|
params: RoleActionParams;
|
|
45
46
|
}
|
|
46
47
|
type Listener = (ctx: ListenerContext) => void;
|
|
48
|
+
export type UserProvider = (args: {
|
|
49
|
+
fields: string[];
|
|
50
|
+
}) => Promise<any>;
|
|
51
|
+
export interface ParseJsonTemplateOptions {
|
|
52
|
+
timezone?: string;
|
|
53
|
+
state?: any;
|
|
54
|
+
userProvider?: UserProvider;
|
|
55
|
+
}
|
|
47
56
|
interface CanArgs {
|
|
48
57
|
role?: string;
|
|
49
58
|
resource: string;
|
|
@@ -104,10 +113,6 @@ export declare class ACL extends EventEmitter {
|
|
|
104
113
|
* @deprecated
|
|
105
114
|
*/
|
|
106
115
|
skip(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc): void;
|
|
107
|
-
/**
|
|
108
|
-
* @internal
|
|
109
|
-
*/
|
|
110
|
-
parseJsonTemplate(json: any, ctx: any): Promise<any>;
|
|
111
116
|
middleware(): (ctx: any, next: any) => Promise<void>;
|
|
112
117
|
/**
|
|
113
118
|
* @internal
|
|
@@ -115,11 +120,20 @@ export declare class ACL extends EventEmitter {
|
|
|
115
120
|
getActionParams(ctx: any): Promise<void>;
|
|
116
121
|
addFixedParams(resource: string, action: string, merger: Merger): void;
|
|
117
122
|
registerSnippet(snippet: SnippetOptions): void;
|
|
118
|
-
/**
|
|
119
|
-
* @internal
|
|
120
|
-
*/
|
|
121
|
-
filterParams(ctx: any, resourceName: any, params: any): any;
|
|
122
123
|
protected addCoreMiddleware(): void;
|
|
123
124
|
protected isAvailableAction(actionName: string): boolean;
|
|
124
125
|
}
|
|
126
|
+
export declare function createUserProvider(options: {
|
|
127
|
+
db?: Database;
|
|
128
|
+
dataSourceManager?: any;
|
|
129
|
+
currentUser?: any;
|
|
130
|
+
}): UserProvider;
|
|
131
|
+
/**
|
|
132
|
+
* @internal
|
|
133
|
+
*/
|
|
134
|
+
export declare function parseJsonTemplate(filter: any, options: ParseJsonTemplateOptions): Promise<any>;
|
|
135
|
+
/**
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
export declare function checkFilterParams(collection: Collection, filter: any): void;
|
|
125
139
|
export {};
|
package/lib/acl.js
CHANGED
|
@@ -37,7 +37,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
37
37
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
38
|
var acl_exports = {};
|
|
39
39
|
__export(acl_exports, {
|
|
40
|
-
ACL: () => ACL
|
|
40
|
+
ACL: () => ACL,
|
|
41
|
+
checkFilterParams: () => checkFilterParams,
|
|
42
|
+
createUserProvider: () => createUserProvider,
|
|
43
|
+
parseJsonTemplate: () => parseJsonTemplate
|
|
41
44
|
});
|
|
42
45
|
module.exports = __toCommonJS(acl_exports);
|
|
43
46
|
var import_utils = require("@nocobase/utils");
|
|
@@ -276,31 +279,6 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
276
279
|
this.allowManager.allow(resourceName, actionName, condition);
|
|
277
280
|
}
|
|
278
281
|
}
|
|
279
|
-
/**
|
|
280
|
-
* @internal
|
|
281
|
-
*/
|
|
282
|
-
async parseJsonTemplate(json, ctx) {
|
|
283
|
-
var _a, _b, _c, _d, _e;
|
|
284
|
-
if (json.filter) {
|
|
285
|
-
(_b = (_a = ctx.logger) == null ? void 0 : _a.info) == null ? void 0 : _b.call(_a, "parseJsonTemplate.raw", JSON.parse(JSON.stringify(json.filter)));
|
|
286
|
-
const timezone = (_c = ctx == null ? void 0 : ctx.get) == null ? void 0 : _c.call(ctx, "x-timezone");
|
|
287
|
-
const state = JSON.parse(JSON.stringify(ctx.state));
|
|
288
|
-
const filter = await (0, import_utils.parseFilter)(json.filter, {
|
|
289
|
-
timezone,
|
|
290
|
-
now: (/* @__PURE__ */ new Date()).toISOString(),
|
|
291
|
-
vars: {
|
|
292
|
-
ctx: {
|
|
293
|
-
state
|
|
294
|
-
},
|
|
295
|
-
$user: getUser(ctx),
|
|
296
|
-
$nRole: /* @__PURE__ */ __name(() => state.currentRole, "$nRole")
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
json.filter = filter;
|
|
300
|
-
(_e = (_d = ctx.logger) == null ? void 0 : _d.info) == null ? void 0 : _e.call(_d, "parseJsonTemplate.parsed", filter);
|
|
301
|
-
}
|
|
302
|
-
return json;
|
|
303
|
-
}
|
|
304
282
|
middleware() {
|
|
305
283
|
const acl = this;
|
|
306
284
|
return /* @__PURE__ */ __name(async function ACLMiddleware(ctx, next) {
|
|
@@ -371,40 +349,11 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
371
349
|
registerSnippet(snippet) {
|
|
372
350
|
this.snippetManager.register(snippet);
|
|
373
351
|
}
|
|
374
|
-
/**
|
|
375
|
-
* @internal
|
|
376
|
-
*/
|
|
377
|
-
filterParams(ctx, resourceName, params) {
|
|
378
|
-
var _a, _b, _c;
|
|
379
|
-
if ((_a = params == null ? void 0 : params.filter) == null ? void 0 : _a.createdById) {
|
|
380
|
-
const collection = ctx.db.getCollection(resourceName);
|
|
381
|
-
if (!collection || !collection.getField("createdById")) {
|
|
382
|
-
throw new import_no_permission_error.NoPermissionError("createdById field not found");
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
if ((_c = (_b = params == null ? void 0 : params.filter) == null ? void 0 : _b.$or) == null ? void 0 : _c.length) {
|
|
386
|
-
const checkCreatedById = /* @__PURE__ */ __name((items) => {
|
|
387
|
-
return items.some(
|
|
388
|
-
(x) => {
|
|
389
|
-
var _a2, _b2;
|
|
390
|
-
return "createdById" in x || ((_a2 = x.$or) == null ? void 0 : _a2.some((y) => "createdById" in y)) || ((_b2 = x.$and) == null ? void 0 : _b2.some((y) => "createdById" in y));
|
|
391
|
-
}
|
|
392
|
-
);
|
|
393
|
-
}, "checkCreatedById");
|
|
394
|
-
if (checkCreatedById(params.filter.$or)) {
|
|
395
|
-
const collection = ctx.db.getCollection(resourceName);
|
|
396
|
-
if (!collection || !collection.getField("createdById")) {
|
|
397
|
-
throw new import_no_permission_error.NoPermissionError("createdById field not found");
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
return params;
|
|
402
|
-
}
|
|
403
352
|
addCoreMiddleware() {
|
|
404
353
|
const acl = this;
|
|
405
354
|
this.middlewares.add(
|
|
406
355
|
async (ctx, next) => {
|
|
407
|
-
var _a, _b, _c, _d;
|
|
356
|
+
var _a, _b, _c, _d, _e, _f;
|
|
408
357
|
const resourcerAction = ctx.action;
|
|
409
358
|
const { resourceName, actionName } = ctx.permission;
|
|
410
359
|
const permission = ctx.permission;
|
|
@@ -417,10 +366,20 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
417
366
|
((_c = ctx.log) == null ? void 0 : _c.debug) && ctx.log.debug("acl params", params);
|
|
418
367
|
try {
|
|
419
368
|
if (params && resourcerAction.mergeParams) {
|
|
420
|
-
const
|
|
421
|
-
const
|
|
369
|
+
const db = ctx.database ?? ctx.db;
|
|
370
|
+
const collection = (_d = db == null ? void 0 : db.getCollection) == null ? void 0 : _d.call(db, resourceName);
|
|
371
|
+
checkFilterParams(collection, params == null ? void 0 : params.filter);
|
|
372
|
+
const parsedFilter = await parseJsonTemplate(params.filter, {
|
|
373
|
+
state: ctx.state,
|
|
374
|
+
timezone: getTimezone(ctx),
|
|
375
|
+
userProvider: createUserProvider({
|
|
376
|
+
db: ctx.db,
|
|
377
|
+
currentUser: (_e = ctx.state) == null ? void 0 : _e.currentUser
|
|
378
|
+
})
|
|
379
|
+
});
|
|
380
|
+
const parsedParams = params.filter ? { ...params, filter: parsedFilter ?? params.filter } : params;
|
|
422
381
|
ctx.permission.parsedParams = parsedParams;
|
|
423
|
-
((
|
|
382
|
+
((_f = ctx.log) == null ? void 0 : _f.debug) && ctx.log.debug("acl parsedParams", parsedParams);
|
|
424
383
|
ctx.permission.rawParams = import_lodash.default.cloneDeep(resourcerAction.params);
|
|
425
384
|
if (parsedParams.appends && resourcerAction.params.fields) {
|
|
426
385
|
for (const queryField of resourcerAction.params.fields) {
|
|
@@ -471,31 +430,99 @@ const _ACL = class _ACL extends import_events.default {
|
|
|
471
430
|
};
|
|
472
431
|
__name(_ACL, "ACL");
|
|
473
432
|
let ACL = _ACL;
|
|
474
|
-
function
|
|
475
|
-
|
|
476
|
-
|
|
433
|
+
function getTimezone(ctx) {
|
|
434
|
+
var _a, _b, _c, _d, _e, _f;
|
|
435
|
+
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"]);
|
|
436
|
+
}
|
|
437
|
+
__name(getTimezone, "getTimezone");
|
|
438
|
+
function createUserProvider(options) {
|
|
439
|
+
var _a, _b, _c, _d, _e;
|
|
440
|
+
const db = options.db ?? ((_e = (_d = (_c = (_b = (_a = options.dataSourceManager) == null ? void 0 : _a.dataSources) == null ? void 0 : _b.get) == null ? void 0 : _c.call(_b, "main")) == null ? void 0 : _d.collectionManager) == null ? void 0 : _e.db);
|
|
441
|
+
const currentUser = options.currentUser;
|
|
477
442
|
return async ({ fields }) => {
|
|
478
|
-
|
|
479
|
-
const userFields = fields.filter((f) => f && db.getFieldByPath("users." + f));
|
|
480
|
-
(_a = ctx.logger) == null ? void 0 : _a.info("filter-parse: ", { userFields });
|
|
481
|
-
if (!ctx.state.currentUser) {
|
|
443
|
+
if (!db) {
|
|
482
444
|
return;
|
|
483
445
|
}
|
|
446
|
+
if (!currentUser) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const userFields = fields.filter((f) => f && db.getFieldByPath("users." + f));
|
|
484
450
|
if (!userFields.length) {
|
|
485
451
|
return;
|
|
486
452
|
}
|
|
487
453
|
const user = await db.getRepository("users").findOne({
|
|
488
|
-
filterByTk:
|
|
454
|
+
filterByTk: currentUser.id,
|
|
489
455
|
fields: userFields
|
|
490
456
|
});
|
|
491
|
-
(_b = ctx.logger) == null ? void 0 : _b.info("filter-parse: ", {
|
|
492
|
-
$user: user == null ? void 0 : user.toJSON()
|
|
493
|
-
});
|
|
494
457
|
return user;
|
|
495
458
|
};
|
|
496
459
|
}
|
|
497
|
-
__name(
|
|
460
|
+
__name(createUserProvider, "createUserProvider");
|
|
461
|
+
function containsCreatedByIdFilter(input, seen = /* @__PURE__ */ new Set()) {
|
|
462
|
+
if (!input) {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
if (Array.isArray(input)) {
|
|
466
|
+
return input.some((item) => containsCreatedByIdFilter(item, seen));
|
|
467
|
+
}
|
|
468
|
+
if (!import_lodash.default.isPlainObject(input)) {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
if (seen.has(input)) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
seen.add(input);
|
|
475
|
+
for (const [key, value] of Object.entries(input)) {
|
|
476
|
+
if (isCreatedByIdKey(key)) {
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
if (containsCreatedByIdFilter(value, seen)) {
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
__name(containsCreatedByIdFilter, "containsCreatedByIdFilter");
|
|
486
|
+
function isCreatedByIdKey(key) {
|
|
487
|
+
return key === "createdById" || key.startsWith("createdById.") || key.startsWith("createdById$");
|
|
488
|
+
}
|
|
489
|
+
__name(isCreatedByIdKey, "isCreatedByIdKey");
|
|
490
|
+
async function parseJsonTemplate(filter, options) {
|
|
491
|
+
if (!filter) {
|
|
492
|
+
return filter;
|
|
493
|
+
}
|
|
494
|
+
const timezone = options == null ? void 0 : options.timezone;
|
|
495
|
+
const state = JSON.parse(JSON.stringify((options == null ? void 0 : options.state) || {}));
|
|
496
|
+
const parsedFilter = await (0, import_utils.parseFilter)(filter, {
|
|
497
|
+
timezone,
|
|
498
|
+
now: (/* @__PURE__ */ new Date()).toISOString(),
|
|
499
|
+
vars: {
|
|
500
|
+
ctx: {
|
|
501
|
+
state
|
|
502
|
+
},
|
|
503
|
+
$user: (options == null ? void 0 : options.userProvider) || (async () => void 0),
|
|
504
|
+
$nRole: /* @__PURE__ */ __name(() => state.currentRole, "$nRole")
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
return parsedFilter;
|
|
508
|
+
}
|
|
509
|
+
__name(parseJsonTemplate, "parseJsonTemplate");
|
|
510
|
+
function checkFilterParams(collection, filter) {
|
|
511
|
+
if (!filter) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
if (!containsCreatedByIdFilter(filter)) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
if (!collection || !collection.getField("createdById")) {
|
|
518
|
+
throw new import_no_permission_error.NoPermissionError("createdById field not found");
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
__name(checkFilterParams, "checkFilterParams");
|
|
498
522
|
// Annotate the CommonJS export names for ESM import in node:
|
|
499
523
|
0 && (module.exports = {
|
|
500
|
-
ACL
|
|
524
|
+
ACL,
|
|
525
|
+
checkFilterParams,
|
|
526
|
+
createUserProvider,
|
|
527
|
+
parseJsonTemplate
|
|
501
528
|
});
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/acl",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.49",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@nocobase/resourcer": "1.9.
|
|
10
|
-
"@nocobase/utils": "1.9.
|
|
9
|
+
"@nocobase/resourcer": "1.9.49",
|
|
10
|
+
"@nocobase/utils": "1.9.49",
|
|
11
11
|
"minimatch": "^5.1.1"
|
|
12
12
|
},
|
|
13
13
|
"repository": {
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
16
16
|
"directory": "packages/acl"
|
|
17
17
|
},
|
|
18
|
-
"gitHead": "
|
|
18
|
+
"gitHead": "b90fa583f837a84067c354a72574e738cc6c3281"
|
|
19
19
|
}
|