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:
Josh 2023-12-06 08:47:11 +00:00 committed by GitHub
parent 295178369f
commit e85a23d937
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 39 additions and 31 deletions

View File

@ -2,12 +2,11 @@ import * as sift from 'sift';
import qs from 'qs';
import { AbilityBuilder, Ability } from '@casl/ability';
import { pick, isNil, isObject } from 'lodash/fp';
// eslint-disable-next-line import/no-extraneous-dependencies, node/no-extraneous-import
import { Permissions as PermissionsTypes } from '@strapi/types';
import type { ParametrizedAction, PermissionRule } from '../../types';
export interface CustomAbilityBuilder {
can(permission: PermissionsTypes.PermissionRule): ReturnType<AbilityBuilder<Ability>['can']>;
buildParametrizedAction: (parametrizedAction: PermissionsTypes.ParametrizedAction) => string;
can(permission: PermissionRule): ReturnType<AbilityBuilder<Ability>['can']>;
buildParametrizedAction: (parametrizedAction: ParametrizedAction) => string;
build(): Ability;
}
@ -32,7 +31,7 @@ const conditionsMatcher = (conditions: unknown) => {
return sift.createQueryTester(conditions, { operations });
};
const buildParametrizedAction = ({ name, params }: PermissionsTypes.ParametrizedAction) => {
const buildParametrizedAction = ({ name, params }: ParametrizedAction) => {
return `${name}?${qs.stringify(params)}`;
};
@ -43,7 +42,7 @@ export const caslAbilityBuilder = (): CustomAbilityBuilder => {
const { can, build, ...rest } = new AbilityBuilder(Ability);
return {
can(permission: PermissionsTypes.PermissionRule) {
can(permission: PermissionRule) {
const { action, subject, properties = {}, condition } = permission;
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)}`;
},

View File

@ -1,10 +1,9 @@
import { cloneDeep, has, isArray } from 'lodash/fp';
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 type { Permission } from '../domain/permission';
import type { PermissionRule } from '../types';
export interface PermissionEngineHooks {
'before-format::validate.permission': ReturnType<typeof hooks.createAsyncBailHook>;
@ -52,7 +51,7 @@ const createBeforeEvaluateContext = (permission: Permission) => ({
});
interface WillRegisterContextParams {
permission: PermissionsTypes.PermissionRule;
permission: PermissionRule;
options: Record<string, unknown>;
}

View File

@ -2,8 +2,6 @@ import _ from 'lodash/fp';
import qs from 'qs';
import { Ability } from '@casl/ability';
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 {
createEngineHooks,
@ -15,6 +13,7 @@ import type { PermissionEngineHooks, HookName } from './hooks';
import * as abilities from './abilities';
import { Permission } from '../domain/permission';
import type { PermissionRule } from '../types';
export { abilities };
@ -30,9 +29,9 @@ export interface Engine {
on(hook: HookName, handler: (...args: any[]) => any): Engine;
generateAbility(permissions: Permission[], options?: object): Promise<Ability>;
createRegisterFunction(
can: (permission: PermissionsTypes.PermissionRule) => unknown,
can: (permission: PermissionRule) => unknown,
options: Record<string, unknown>
): (permission: PermissionsTypes.PermissionRule) => Promise<unknown>;
): (permission: PermissionRule) => Promise<unknown>;
}
export interface EngineParams {
@ -42,7 +41,7 @@ export interface EngineParams {
interface EvaluateParams {
options: Record<string, unknown>;
register: (permission: PermissionsTypes.PermissionRule) => Promise<unknown>;
register: (permission: PermissionRule) => Promise<unknown>;
permission: Permission;
}
@ -179,7 +178,7 @@ const newEngine = (params: EngineParams): Engine => {
* used to register a permission in the ability builder
*/
createRegisterFunction(can, options: Record<string, unknown>) {
return async (permission: PermissionsTypes.PermissionRule) => {
return async (permission: PermissionRule) => {
const hookContext = createWillRegisterContext({ options, permission });
await state.hooks['before-register.permission'].call(hookContext);

View 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>;
}

View File

@ -50,11 +50,9 @@ export {
};
declare global {
// @ts-expect-error - global strapi variable is also defined in the index.d.ts file
var strapi: LoadedStrapi;
namespace NodeJS {
interface Global {
// @ts-expect-error - global strapi variable is also defined in the index.d.ts file
strapi: LoadedStrapi;
}
}

View File

@ -1,14 +1,8 @@
import { Subject } from '@casl/ability';
import type { engine } from '@strapi/permissions';
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>;
}
type PermissionRule = Parameters<engine.abilities.CustomAbilityBuilder['can']>[0];
type ParametrizedAction = Parameters<
engine.abilities.CustomAbilityBuilder['buildParametrizedAction']
>[0];
export type { PermissionRule, ParametrizedAction };