mirror of
https://github.com/strapi/strapi.git
synced 2025-11-23 13:40:58 +00:00
fix(permissions): circular dependency (#18986)
* fix(permissions): circular dependency * Apply suggestions from code review Co-authored-by: Ben Irvin <ben@innerdvations.com> * Apply suggestions from code review Co-authored-by: Jean-Sébastien Herbaux <jean-sebastien.herbaux@epitech.eu> --------- Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jean-Sébastien Herbaux <jean-sebastien.herbaux@epitech.eu>
This commit is contained in:
parent
295178369f
commit
e85a23d937
@ -2,12 +2,11 @@ import * as sift from 'sift';
|
|||||||
import qs from 'qs';
|
import qs from 'qs';
|
||||||
import { AbilityBuilder, Ability } from '@casl/ability';
|
import { AbilityBuilder, Ability } from '@casl/ability';
|
||||||
import { pick, isNil, isObject } from 'lodash/fp';
|
import { pick, isNil, isObject } from 'lodash/fp';
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies, node/no-extraneous-import
|
import type { ParametrizedAction, PermissionRule } from '../../types';
|
||||||
import { Permissions as PermissionsTypes } from '@strapi/types';
|
|
||||||
|
|
||||||
export interface CustomAbilityBuilder {
|
export interface CustomAbilityBuilder {
|
||||||
can(permission: PermissionsTypes.PermissionRule): ReturnType<AbilityBuilder<Ability>['can']>;
|
can(permission: PermissionRule): ReturnType<AbilityBuilder<Ability>['can']>;
|
||||||
buildParametrizedAction: (parametrizedAction: PermissionsTypes.ParametrizedAction) => string;
|
buildParametrizedAction: (parametrizedAction: ParametrizedAction) => string;
|
||||||
build(): Ability;
|
build(): Ability;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ const conditionsMatcher = (conditions: unknown) => {
|
|||||||
return sift.createQueryTester(conditions, { operations });
|
return sift.createQueryTester(conditions, { operations });
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildParametrizedAction = ({ name, params }: PermissionsTypes.ParametrizedAction) => {
|
const buildParametrizedAction = ({ name, params }: ParametrizedAction) => {
|
||||||
return `${name}?${qs.stringify(params)}`;
|
return `${name}?${qs.stringify(params)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -43,7 +42,7 @@ export const caslAbilityBuilder = (): CustomAbilityBuilder => {
|
|||||||
const { can, build, ...rest } = new AbilityBuilder(Ability);
|
const { can, build, ...rest } = new AbilityBuilder(Ability);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
can(permission: PermissionsTypes.PermissionRule) {
|
can(permission: PermissionRule) {
|
||||||
const { action, subject, properties = {}, condition } = permission;
|
const { action, subject, properties = {}, condition } = permission;
|
||||||
const { fields } = properties;
|
const { fields } = properties;
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ export const caslAbilityBuilder = (): CustomAbilityBuilder => {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
buildParametrizedAction({ name, params }: PermissionsTypes.ParametrizedAction) {
|
buildParametrizedAction({ name, params }: ParametrizedAction) {
|
||||||
return `${name}?${qs.stringify(params)}`;
|
return `${name}?${qs.stringify(params)}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import { cloneDeep, has, isArray } from 'lodash/fp';
|
import { cloneDeep, has, isArray } from 'lodash/fp';
|
||||||
import { hooks } from '@strapi/utils';
|
import { hooks } from '@strapi/utils';
|
||||||
// eslint-disable-next-line node/no-extraneous-import
|
|
||||||
import type { Permissions as PermissionsTypes } from '@strapi/types';
|
|
||||||
|
|
||||||
import * as domain from '../domain';
|
import * as domain from '../domain';
|
||||||
import type { Permission } from '../domain/permission';
|
import type { Permission } from '../domain/permission';
|
||||||
|
import type { PermissionRule } from '../types';
|
||||||
|
|
||||||
export interface PermissionEngineHooks {
|
export interface PermissionEngineHooks {
|
||||||
'before-format::validate.permission': ReturnType<typeof hooks.createAsyncBailHook>;
|
'before-format::validate.permission': ReturnType<typeof hooks.createAsyncBailHook>;
|
||||||
@ -52,7 +51,7 @@ const createBeforeEvaluateContext = (permission: Permission) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
interface WillRegisterContextParams {
|
interface WillRegisterContextParams {
|
||||||
permission: PermissionsTypes.PermissionRule;
|
permission: PermissionRule;
|
||||||
options: Record<string, unknown>;
|
options: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,6 @@ import _ from 'lodash/fp';
|
|||||||
import qs from 'qs';
|
import qs from 'qs';
|
||||||
import { Ability } from '@casl/ability';
|
import { Ability } from '@casl/ability';
|
||||||
import { providerFactory } from '@strapi/utils';
|
import { providerFactory } from '@strapi/utils';
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies, node/no-extraneous-import
|
|
||||||
import { Permissions as PermissionsTypes } from '@strapi/types';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createEngineHooks,
|
createEngineHooks,
|
||||||
@ -15,6 +13,7 @@ import type { PermissionEngineHooks, HookName } from './hooks';
|
|||||||
|
|
||||||
import * as abilities from './abilities';
|
import * as abilities from './abilities';
|
||||||
import { Permission } from '../domain/permission';
|
import { Permission } from '../domain/permission';
|
||||||
|
import type { PermissionRule } from '../types';
|
||||||
|
|
||||||
export { abilities };
|
export { abilities };
|
||||||
|
|
||||||
@ -30,9 +29,9 @@ export interface Engine {
|
|||||||
on(hook: HookName, handler: (...args: any[]) => any): Engine;
|
on(hook: HookName, handler: (...args: any[]) => any): Engine;
|
||||||
generateAbility(permissions: Permission[], options?: object): Promise<Ability>;
|
generateAbility(permissions: Permission[], options?: object): Promise<Ability>;
|
||||||
createRegisterFunction(
|
createRegisterFunction(
|
||||||
can: (permission: PermissionsTypes.PermissionRule) => unknown,
|
can: (permission: PermissionRule) => unknown,
|
||||||
options: Record<string, unknown>
|
options: Record<string, unknown>
|
||||||
): (permission: PermissionsTypes.PermissionRule) => Promise<unknown>;
|
): (permission: PermissionRule) => Promise<unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EngineParams {
|
export interface EngineParams {
|
||||||
@ -42,7 +41,7 @@ export interface EngineParams {
|
|||||||
|
|
||||||
interface EvaluateParams {
|
interface EvaluateParams {
|
||||||
options: Record<string, unknown>;
|
options: Record<string, unknown>;
|
||||||
register: (permission: PermissionsTypes.PermissionRule) => Promise<unknown>;
|
register: (permission: PermissionRule) => Promise<unknown>;
|
||||||
permission: Permission;
|
permission: Permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +178,7 @@ const newEngine = (params: EngineParams): Engine => {
|
|||||||
* used to register a permission in the ability builder
|
* used to register a permission in the ability builder
|
||||||
*/
|
*/
|
||||||
createRegisterFunction(can, options: Record<string, unknown>) {
|
createRegisterFunction(can, options: Record<string, unknown>) {
|
||||||
return async (permission: PermissionsTypes.PermissionRule) => {
|
return async (permission: PermissionRule) => {
|
||||||
const hookContext = createWillRegisterContext({ options, permission });
|
const hookContext = createWillRegisterContext({ options, permission });
|
||||||
|
|
||||||
await state.hooks['before-register.permission'].call(hookContext);
|
await state.hooks['before-register.permission'].call(hookContext);
|
||||||
|
|||||||
19
packages/core/permissions/src/types.ts
Normal file
19
packages/core/permissions/src/types.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* These were imported from `@strapi/types` but if we do that
|
||||||
|
* it becomes a circular dependency. This is the source of truth,
|
||||||
|
* they're re-exported from `@strapi/types` for convenience.
|
||||||
|
*/
|
||||||
|
import type { Subject } from '@casl/ability';
|
||||||
|
|
||||||
|
export interface ParametrizedAction {
|
||||||
|
name: string;
|
||||||
|
params: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
export interface PermissionRule {
|
||||||
|
action: string | ParametrizedAction;
|
||||||
|
subject?: Subject | null;
|
||||||
|
properties?: {
|
||||||
|
fields?: string[];
|
||||||
|
};
|
||||||
|
condition?: Record<string, unknown>;
|
||||||
|
}
|
||||||
@ -50,11 +50,9 @@ export {
|
|||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// @ts-expect-error - global strapi variable is also defined in the index.d.ts file
|
|
||||||
var strapi: LoadedStrapi;
|
var strapi: LoadedStrapi;
|
||||||
namespace NodeJS {
|
namespace NodeJS {
|
||||||
interface Global {
|
interface Global {
|
||||||
// @ts-expect-error - global strapi variable is also defined in the index.d.ts file
|
|
||||||
strapi: LoadedStrapi;
|
strapi: LoadedStrapi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,8 @@
|
|||||||
import { Subject } from '@casl/ability';
|
import type { engine } from '@strapi/permissions';
|
||||||
|
|
||||||
export interface ParametrizedAction {
|
type PermissionRule = Parameters<engine.abilities.CustomAbilityBuilder['can']>[0];
|
||||||
name: string;
|
type ParametrizedAction = Parameters<
|
||||||
params: Record<string, unknown>;
|
engine.abilities.CustomAbilityBuilder['buildParametrizedAction']
|
||||||
}
|
>[0];
|
||||||
export interface PermissionRule {
|
|
||||||
action: string | ParametrizedAction;
|
export type { PermissionRule, ParametrizedAction };
|
||||||
subject?: Subject | null;
|
|
||||||
properties?: {
|
|
||||||
fields?: string[];
|
|
||||||
};
|
|
||||||
condition?: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user