@nocobase/acl 2.2.0-beta.12 → 2.2.0-beta.14

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.
Files changed (3) hide show
  1. package/lib/acl.d.ts +18 -0
  2. package/lib/acl.js +153 -71
  3. 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
- let resourceName = rawResourceName;
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
- var _a;
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
- let resourceName = rawResourceName;
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, _c, _d, _e, _f;
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
- if (params && resourcerAction.mergeParams) {
375
- const db = ctx.database ?? ctx.db;
376
- const collection = (_d = db == null ? void 0 : db.getCollection) == null ? void 0 : _d.call(db, resourceName);
377
- checkFilterParams(collection, params == null ? void 0 : params.filter);
378
- const parsedFilter = await parseJsonTemplate(params.filter, {
379
- state: ctx.state,
380
- timezone: getTimezone(ctx),
381
- userProvider: createUserProvider({
382
- db: ctx.db,
383
- currentUser: (_e = ctx.state) == null ? void 0 : _e.currentUser
384
- })
385
- });
386
- const parsedParams = params.filter ? { ...params, filter: parsedFilter ?? params.filter } : params;
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-beta.12",
3
+ "version": "2.2.0-beta.14",
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": "ad8ed32d47eaec2dc56f15999934f720787d5070"
21
+ "gitHead": "1ef021f3ce0a84469e40f181a19551a50b6f850c"
22
22
  }